2015-10-11 2 views
1

Я пытаюсь создать два потока, чтобы действовать как счетчики. Когда один поток уменьшает свой счетчик, он должен переключать значение поля общего логического флага, вызывать метод notifyAll() и выпустить другой поток из вызываемого метода wait(). Логическое поле служит средством для предотвращения тупиковой ситуации, то есть один поток будет вызывать метод wait(), когда поле флага имеет значение true, другой поток будет вызывать его, когда поле флага имеет значение false. Вы можете увидеть, как я запускаю потоки, созданные из этого класса, а также ожидаемый результат ниже. Проблема в том, что оба потока застревают в методе wait() в то же время, и проходит только первая строка вывода.Почему мой поток не возвращается из wait() после вызова notifyAll() из другого потока?

Ожидаемый результат:

Thread No.1 4 
Thread No.2 4 
Thread No.1 3 
Thread No.2 3 
Thread No.1 2 
Thread No.2 2 
Thread No.1 1 
Thread No.2 1 
Thread No.1 0 
Thread No.2 0 

Фактический выход:

Thread No.2 4 

Счетчик класса:

public class CounterThread implements Runnable { 
    private long counter; 
    private static int threadNumber = 0; 
    private int index = 0; 
    private static boolean flag = true; 
    private boolean logic; 

    public CounterThread(long counter, boolean logic) { 

     index = ++threadNumber; 
     this.counter = counter; 
     this.logic = logic; 
    } 

    private synchronized void toggleFlag() { 
     flag = !flag; 
     notifyAll(); 
    } 

    @Override 
    public synchronized void run() { 
     while (counter > 0) { 
      while (flag==logic) { 
       try { 
        wait(); 
       } catch (InterruptedException e) { 

       } 
      } 
      counter--; 
      System.out.println("Thread No. " + index + " " +counter); 
      toggleFlag(); 
     } 
    } 
} 

Как я запустить его:

public final class CounterThreadRun { 

    public static void main(String[] args) { 
     CounterThread counter1 = new CounterThread(5, true); 
     CounterThread counter2 = new CounterThread(5, false); 
     Thread thread1 = new Thread(counter1); 
     Thread thread2 = new Thread(counter2); 
     thread1.start(); 
     thread2.start(); 
    } 
} 
+0

FYI «Вопросы, требующие помощи по отладке (« почему этот код не работает? ») Должны включать в себя желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для воспроизведения в самом вопросе. Вопросы без четкой проблемы утверждение не полезно для других читателей ». – bhspencer

+0

некоторые упрощения - toggle -' flag =! flag', wait - 'while (флаг == logic)' – ZhongYu

+0

@ bayou.io спасибо, я упростил его – SUBmarinoff

ответ

1

Потому что вы не уведомляете нить, которая ждет. Вы только уведомляете текущий поток, т. Е. Себя. Вам нужен общий объект, возможно, static в классе, который используется как для wait(), так и для notifyAll().

+0

Незначительный нит-выбор, но вы действительно говорите здесь, что каждый поток в примере имеет свой экземпляр «CounterThread», и они не «уведомляют»() «экземпляр друг друга». Я хочу сказать, что мы не уведомляем _threads_, мы уведомляем _objects_, по которому могут ждать другие потоки. Отличие заключается в том, что когда мы говорим, что делаем что-то в потоке (например, прерывая поток), это означает, что мы знаем, к какому потоку мы это делаем. Но вызывающий 'o.notify()' часто не знает и не заботится о том, какой поток (если он есть) будет просыпаться. –

Смежные вопросы