Итак, вот код. В принципе, если мы изменим классы ReadCalculation и Calculator для расширения Thread вместо внедрения Runnable, нам нужно будет создать эти классы и передать их в новый объект потока или просто вызвать start() на них.Различное поведение при реализации Runnable вместо продолжения Thread
Calculator calc = new Calculator();
new ReadCalculation(calc).start();
new ReadCalculation(calc).start();
calc.start();
Ничего особенного до сих пор .. Но когда вы выполняете эту крошечную программу, есть огромный шанс, что ваши потоки будут оставаться заблокированными «Ожидание расчета ...» если мы будем над Runnable реализации над простирающимся класс Thread.
Если мы расширим класс Thread вместо реализации Runnable, поведение будет правильным без каких-либо признаков состояния гонки. Любые идеи, по которым может быть источником такого поведения?
public class NotifyAllAndWait {
public static void main(String[] args) {
Calculator calc = new Calculator();
Thread th01 = new Thread(new ReadCalculation(calc));
th01.start();
Thread th02 = new Thread(new ReadCalculation(calc));
th02.start();
Thread calcThread = new Thread(calc);
calcThread.start();
}
}
class ReadCalculation implements Runnable {
private Calculator calc = null;
ReadCalculation(Calculator calc) {
this.calc = calc;
}
@Override
public void run() {
synchronized (calc) {
try {
System.out.println(Thread.currentThread().getName() + " Waiting for calculation...");
calc.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Total: " + calc.getTotal());
}
}
}
class Calculator implements Runnable {
private int total = 0;
@Override
public void run() {
synchronized(this) {
System.out.println(Thread.currentThread().getName() + " RUNNING CALCULATION!");
for(int i = 0; i < 100; i = i + 2){
total = total + i;
}
notifyAll();
}
}
public int getTotal() {
return total;
}
}
Я не могу ссылаться на какую-либо часть языка или спецификацию JVM, которая может быть здесь воспроизведена, но наиболее вероятной практикой является то, что исходный код 'Thread' занимает очень много блокировок для обоих потоков. class' и текущий экземпляр 'Thread'. Вы блокируете экземпляр калькулятора как внутри, так и снаружи 'calc'. Эти блокировки могут не мешать блокировке внутри 'Thread', когда вы используете выделенную целевую Runnable (только что проверено: ни один код в реализации Android Thread не блокирует переданный Runnable), но, безусловно, повлияет на порядок выполнения при расширении Thread. – user1643723