2014-01-12 4 views
0

пример: wait() и notify() в Java Concurrency. Мои теоретические знания об этом не объясняют мне этот код, и я не могу объяснить, почему это дает мне непонятый результат.Как понять этот простой пример потока?

Итак, это код, чтобы получить представление:

public class ExampleOne { 
    public static void main(String[] args) { 
     Test b = new Test(); 
     b.start(); 
     synchronized(b){ 
      try{  
       b.wait(); 
      } catch(InterruptedException ex){ 
       ex.printStackTrace(); 
      } 
      System.out.println(b.total); 
     } 
    } 
} 

class Test extends Thread { 
    int total; 

    @Override 
    public void run(){ 
     synchronized(this){ 
      for(int i =0;i<50;i++){ 
       total+=i; 
       System.out.println("I am here"); 
      } 
      notify(); 
     } 
    } 
} 

Результат: 4950

Итак, как понять этот процесс (как total может быть 4950)?

Я понимаю, что если я звоню wait(), он останавливает поток объекта, который вызвал этот метод, и разбудил его, затем другой поток вызывает notify(). Кроме того, блок synchronized() ограничивает потоки и принимает только один поток за один раз.

  • Поэтому, когда поток вызывает уведомит(), он становится неактивным, пока другие вызовы нити ждать()?

  • Как wait() и notify() играют свою роль в этом коде? Также synchronized() блок?

  • Итак, сколько потоков создано в этом коде?

Я смущен об этом. Помогите мне разобраться.

+0

'wait()' на объекте помещает вызывающий поток в состояние ожидания, пока на тот же объект не вызывается 'notify()' или 'notifyAll()'. Это не поток объектов. Это поток, который получает блокировку объекта и называет 'wait()' на нем. – ahanin

+0

Остерегайтесь этого кода: если поток 'Test' вызывает' notify() 'перед тем, как основной поток вызывает' wait() ', основной поток будет ждать вечно. Я предлагаю вам переместить 'b.start' ** внутри **' synchronized (b) ', чтобы избежать этой потенциальной проблемы. – m0skit0

ответ

5

Если я позвоню ожидание() останавливает нить объекта, который назвал этот метод и проснулся тогда другой поток вызовов уведомить()

справа. notify()илиnotifyAll() на такой же экземпляр объекта пробудит поток.

Так что, когда поток вызывает notify(), он становится неактивным, пока другой поток не вызывает wait()?

No. Уведомлять, просто сигнализирует поток, ожидающий того же объекта. Поток, который вызывает notify(), продолжает работать и не освобождает блокировку synchronized, которую он удерживает.

Как wait() и notify() играют свою роль в этом коде?

Без ожидания/уведомления. основная нить не дождалась завершения вычисления, поэтому, вероятно, будет напечатана 0.

Также синхронизирован() блок?

При использовании wait() или notify() вы должны быть в synchronized блоке. Монитором, связанным с экземпляром объекта, является synchronized, который находится в ожидании и уведомляется.Кроме того, блок synchronized обеспечивает синхронизацию памяти, поэтому основные потоки видят изменения в поле notify. Каждый поток имеет кэш памяти, и для потоков необходимо создать механизмы для публикации изменений и увидеть изменения в полях, созданных другими потоками.

Итак, сколько потоков создано в этом коде?

1 нить создана вашим кодом, и основной поток автоматически создается JVM.

Важно понимать, что в этом коде есть условие гонки. Возможно, что новый поток запустится, прокрутите цикл, вызовите уведомление и выйдите из до. На самом деле главный поток вызывает wait. Это маловероятно, потому что запуск потока занимает некоторое время, но это может произойти. В этом случае основной поток застрял бы в wait навсегда, потому что его никто не должен уведомлять.

Пара Другие комментарии:

  • Я рекомендовал использовать this.notify(). Всегда полезно повторить, что такое notified.
  • Как указывает @JBNizet, лучше использовать объект блокировки private final, а не объект Thread.
  • Всегда рекомендуется определять класс, который implements Runnable, в отличие от выдвижной нити. Тогда вы сделали бы new Thread(new TestRunnable()); ....
+0

Он назвал бы это один раз, но остался бы в ожидании состояния навсегда. – ahanin

+0

«В этом случае главная нить будет называть« вечно »- казалась мне бесконечной петлей. – ahanin

+0

О, я вижу, правильно. Изменено. Спасибо @ahanin. – Gray

2

В дополнение к отличной ответ Грея, вот что происходит:

Основной поток:

----------------------------------------------------> 
|     |       | 
start Test thread waits until notified   wakes up and prints the result 

Тест Тема:

      ------------------------> 
         |      | 
         starts running  notifies main thread 
         computes the sum 

Также обратите внимание, что это обычно считается плохой практикой называть wait() и notify() в экземпляре темы. Вместо этого следует использовать общий объект, действующий как блокировка. notifyAll() следует отдать предпочтение обычно или даже лучше, следует использовать абстракцию более высокого уровня, например CountDownLatch.

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