Изничально код имеет ДЕДЛОКИ тк один синхронизированный метод одного объекта вызывается внутни другого синхронизированного
Автор предлагает решение,которое УБИРАЕТ ДЕДЛОКИ, но у меня вопросы к ПОТОКОБЕЗОПАСТНОСТИ такого решения(изменению автор подвергает только 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);
}
}package com.javarush.task.task27.task2708;
import java.util.Set;
/*
Убираем deadLock используя открытые вызовы
*/
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();
}
}