Изничально код имеет ДЕДЛОКИ тк один синхронизированный метод одного объекта вызывается внутни другого синхронизированного Автор предлагает решение,которое УБИРАЕТ ДЕДЛОКИ, но у меня вопросы к ПОТОКОБЕЗОПАСТНОСТИ такого решения(изменению автор подвергает только 3 метода , ниже напишу какие) У меня вопрос почему ЕСЛИ мы убираем слово synchronized у метода public synchronized void up(Apartment apartment) в классе RealEstate и public void revalidate(boolean isEmpty) в классе Apartment,а также в методе класса RealEstate
public synchronized void revalidate() {
        activeApartments.clear();
        for (Apartment apartment : allApartments) {
            boolean randomValue = Math.random() * 2 % 2 == 0;
            apartment.revalidate(randomValue);
        }
мы синхронизацию выносим из сигнатуры внутрь метода

    public void revalidate() {
        activeApartments.clear();
        for (Apartment apartment : allApartments) {
            boolean randomValue = Math.random() * 2 % 2 == 0;
            synchronized (apartment) {
                apartment.revalidate(randomValue);
            }
        }
    }
Автор говорит,что после изменений код стал потокобезопастным, но Я СЧИТАЮ что это не так , ведь внутри методов разные потоки(которые мы создаем в классе Solution) меняют общие ресурсы(например поле realEstate меняется несколькими потоками,и activeApartments.add(apartment) тоже добавляет в коллекцию activeApartments в разных потоках) Да и метод объекта RealEstate revalidate(), который перезаполняет список свободных квартир, В АВТОРСКОМ решении при использовании двумя нитями получается что первая нить еще не заполнила список свободных квартир, а следующая нить его уже очистила Ниже прилагаю текст АВТОРСКОГО решения(состоит из ТРЕХ классов) и после него код классов ДО авторского решения, на Текст класса Solution внимание можете почти НЕ обращать, он НЕ МЕНЯЕТСЯ ------ДО--------------ДО-----------------ДО--------------------
public class Solution {
    public static void main(String[] args) {
        final long deadline = System.currentTimeMillis() + 5000; //waiting for 5 sec

        final RealEstate realEstate = new RealEstate();
        Set<Apartment> allApartments = realEstate.getAllApartments();

        final Apartment[] apartments = allApartments.toArray(new Apartment[allApartments.size()]);

        for (int i = 0; i < 20; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        realEstate.revalidate();
                    }
                }
            }, "RealEstateThread" + i).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < apartments.length; i++) {
                        apartments[i].revalidate(true);
                    }
                }
            }, "ApartmentThread" + i).start();
        }

        Thread deamonThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (System.currentTimeMillis() < deadline)
                    try {
                        Thread.sleep(2);
                    } catch (InterruptedException ignored) {
                    }
                System.out.println("Deadlock occurred");
            }
        });
        deamonThread.setDaemon(true);
        deamonThread.start();
    }
}
public class Apartment {
    private String location;
    private final RealEstate realEstate;

    public Apartment(RealEstate realEstate) {
        this.realEstate = realEstate;
        setLocation(String.valueOf(Math.random() * 10));
    }

    public synchronized String getLocation() {
        return location;
    }

    public synchronized void setLocation(String location) {
        this.location = location;
    }

    public synchronized void revalidate(boolean isEmpty) {
        if (isEmpty)
            realEstate.up(this);
    }
}
public class RealEstate {

    private final Set<Apartment> allApartments;
    private final Set<Apartment> activeApartments;

    public RealEstate() {
        allApartments = new HashSet();
        activeApartments = new HashSet();

        //add some data
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
    }

    public Set<Apartment> getAllApartments() {
        return allApartments;
    }

    public synchronized void up(Apartment apartment) {
        activeApartments.add(apartment);
    }

    public synchronized void revalidate() {
        activeApartments.clear();
        for (Apartment apartment : allApartments) {
            boolean randomValue = Math.random() * 2 % 2 == 0;
            apartment.revalidate(randomValue);
        }
    }
}
------ПОСЛЕ------------ПОСЛЕ-------------ПОСЛЕ--------

public class RealEstate {
    private final Set<Apartment> allApartments;
    private final Set<Apartment> activeApartments;

    public RealEstate() {
        allApartments = new HashSet();
        activeApartments = new HashSet();

        //add some data
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
        allApartments.add(new Apartment(this));
    }

    public Set<Apartment> getAllApartments() {
        return allApartments;
    }

    public void up(Apartment apartment) {
        activeApartments.add(apartment);
    }

    public void revalidate() {
        activeApartments.clear();
        for (Apartment apartment : allApartments) {
            boolean randomValue = Math.random() * 2 % 2 == 0;
            synchronized (apartment) {
                apartment.revalidate(randomValue);
            }
        }
    }
}

public class Apartment {
    private String location;
    private final RealEstate realEstate;

    public Apartment(RealEstate realEstate) {
        this.realEstate = realEstate;
        setLocation(String.valueOf(Math.random() * 10));
    }

    public synchronized String getLocation() {
        return location;
    }

    public synchronized void setLocation(String location) {
        this.location = location;
    }

    public void revalidate(boolean isEmpty) {
        if (isEmpty)
            realEstate.up(this);
    }
}