wait не получает notify на случайной итерации

141
13 марта 2018, 02:42

Задача: Сделать 3 потока, которые будут выполнятся друг за другом, то есть 2-ой поток идет за 1-ым, а 3-ий за вторым, 1-ый за 3-им.Задача должна быть реализована без флагов, только wait,notify.
Проблема: На случайной итерации цикла (1000-10000) программа встает на wait любого потока. Но до этого момента все потоки работают правильно.
Для лучшего понимания, код стоит читать снизу вверх.

    class FirstWorker implements Runnable {
        @Override
        public void run(){
            for (int i = 0; i < a; i++) {
                System.out.println(Thread.currentThread().getName() + " ZABIVAU " + i);
                synchronized (mutex){
                    mutex.notify();
                }
                synchronized (mutex3){
                    try {
                        mutex3.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    class SecondWorker implements Runnable{
        @Override
        public void run() {
            new Thread(new FirstWorker()).start();
            for (int i = 0; i < a; i++) {
                System.out.println(Thread.currentThread().getName() + " SAJAU " + i);
                synchronized (mutex3){
                    mutex3.notify();
                }
                synchronized (mutex2){
                    try {
                        mutex2.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    class ThirdWorker implements Runnable{
        @Override
        public void run() {
            new Thread(new SecondWorker()).start();               
            for (int i = 0; i < a; i++) {
                System.out.println(Thread.currentThread().getName()+" KOPAU " + i);
                synchronized (mutex2){
                    mutex2.notify();
                }
                synchronized (mutex){
                    try {
                        mutex.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public static void main(String[] args){
          Object mutex = new Object();
          Object mutex2 = new Object();
          Object mutex3 = new Object();
          //тут объявляю 3 класса описанные выше
          new Thread(new ThirdWorker()).start();
    }
Answer 1

Прям детектив

synchronized (mutex){
      mutex.notify();
    }
//<--HERE
    synchronized (mutex3){
      try {
        mutex3.wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

Представьте что поток дошел до точки HERE и переключился на поток ThirdWorker, который только что разбудили по замку mutex. Поток ThirdWorker в свою очередь будит SecondWorker и сам засыпает по замку mutex.

Поток SecondWorker просыпается и пытается разбудить FirstWorker по замку mutex3, но он и так уже не спит, поэтому notify просто игнорируется. Поток SecondWorker тем временем засыпает по замку mutex2. Далее программе ничего не остается как переключается на единственный неспящий поток - FirstWorker в точке HERE, но тот уже никого не будит и просто засыпает по замку mutex3. Всё deadlock.

READ ALSO
Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1

Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1

андроид студио в интеллии, выскакивает такая ошибка:

151
Java Instrumentation

Java Instrumentation

Я создал jar файл для java агента для того чтобы использовать его в своем приложении , java агент подсчитывает размер объекта с помощью класса...

133
Как правильно передать данные из Fragment во ViewModel?

Как правильно передать данные из Fragment во ViewModel?

ЗдравствуйтеЕсть фрагмент, внутри которого RecyclerView, EditText и Button

129