2009-05-20 2 views
120

У меня есть 2 матрицы, и мне нужно их умножить, а затем распечатать результаты каждой ячейки. Как только одна ячейка готова, мне нужно ее распечатать, но, например, мне нужно распечатать ячейку [0] [0] до ячейки [2] [0], даже если результат [2] [0] готов первым , Поэтому мне нужно распечатать его по заказу. Так что моя идея заключается в том, чтобы сделать поток в состояние ожидания принтера до тех пор, multiplyThread не уведомит его о том, что соответствующая ячейка готова для печати, а затем printerThread напечатает ячейку и вернуться к ожиданию и так далее ..Как использовать wait и уведомлять в Java?

Так что я это нить, которая делает умножение:

public void run() 
{ 
    int countNumOfActions = 0; // How many multiplications have we done 
    int maxActions = randomize(); // Maximum number of actions allowed 

    for (int i = 0; i < size; i++) 
    {  
     result[rowNum][colNum] = result[rowNum][colNum] + row[i] * col[i]; 
     countNumOfActions++; 
     // Reached the number of allowed actions 
     if (countNumOfActions >= maxActions) 
     { 
      countNumOfActions = 0; 
      maxActions = randomize(); 
      yield(); 
     } 
    } 
    isFinished[rowNum][colNum] = true; 
    notify(); 
} 

тему, которая выводит результат каждой ячейки:

public void run() 
{ 
    int j = 0; // Columns counter 
    int i = 0; // Rows counter 
    System.out.println("The result matrix of the multiplication is:"); 

    while (i < creator.getmThreads().length) 
    { 
     synchronized (this) 
     { 
      try 
      { 
       this.wait(); 
      } 
      catch (InterruptedException e1) 
      { 
      } 
     } 
     if (creator.getmThreads()[i][j].getIsFinished()[i][j] == true) 
     { 
      if (j < creator.getmThreads()[i].length) 
      { 
       System.out.print(creator.getResult()[i][j] + " "); 
       j++; 
      } 
      else 
      { 
       System.out.println(); 
       j = 0; 
       i++; 
       System.out.print(creator.getResult()[i][j] + " "); 
      } 
     } 
    } 

Теперь бросает мне эти исключения:

Exception in thread "Thread-9" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-6" Exception in thread "Thread-4" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-5" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-7" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at multiplyThread.run(multiplyThread.java:49) 

строка 49 в multiplyThread является «уведомлять()». Я думаю, мне нужно использовать синхронизированную по-разному, но я не уверен, как это сделать.

Если кто-нибудь может помочь этому коду работать, я буду очень признателен.

ответ

203

Чтобы быть в состоянии назвать notify() вам нужно синхронизировать на одном объекте.

synchronized (someObject) { 
    someObject.wait(); 
} 

/* different thread/object */ 
synchronized (someObject) { 
    someObject.notify(); 
} 
+0

Это быстрее, чем пользовательские блокировки, такие как while (otherThread.notReady) {}? Или медленнее? –

+26

Параметр 'while (! JobCompleted);' обычно является плохой идеей, потому что он связывает ваш процессор с 100% постоянной проверкой одной и той же переменной (см. [Здесь] (http://stackoverflow.com/a/1676030/57508)) –

+5

'while (! JobCompleted) Thread.sleep (5); 'не имеет этой проблемы – BeniBela

6

notify() необходимо синхронизировать, а

+0

:-) ясно и прямо в точку - ура! – Premraj

7

Вы можете только позвонить оповещению об объектах, где у вас есть их монитор. Поэтому вам нужно что-то вроде

synchronized(threadObject) 
{ 
    threadObject.notify(); 
} 
20

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

Возможно, стоило бы измерить это время, прежде чем выполнять относительно сложную работу с резьбой?

Если вам нужно его вставить, я бы создавал потоки «n» для выполнения умножения ячеек (возможно, «n» - количество доступных вам ядер), а затем используйте механизмы и Future для одновременно отправлять множественные умножения.

Таким образом, вы можете оптимизировать работу на основе количества ядер, и вы используете инструменты потоковой передачи Java на более высоком уровне (что должно облегчить жизнь). Запишите результаты обратно в принимающую матрицу, а затем просто напечатайте это, как только все ваши будущие задачи будут завершены.

+1

+1 @Greg Я думаю, вам стоит взглянуть на пакет java.util.concurrent, как указал Брайан. – ATorras

+1

+1 а также ознакомьтесь с этой книгой, которая также научит вас правильному использованию wait() и notify() http://jcip.net/ – Chii

+0

Downvoted why? –

62

При использовании wait и notify или notifyAll методов в Java следующих вещей необходимо помнить:

  1. Использование notifyAll вместо notify, если вы ожидаете, что более чем один поток будет ждать замка.
  2. The wait and notify methods must be called in a synchronized context. См. Ссылку для более подробного объяснения.
  3. Всегда вызывайте метод wait() в цикле, потому что если несколько потоков ждут блокировки, и один из них получил блокировку и сбросил условие, то другие потоки должны проверить условие после того, как они проснутся, чтобы узнать, нужны ли они снова подождать или начать обработку.
  4. Используйте этот же объект для звонка wait() и notify() метод; каждый объект имеет свой собственный замок, поэтому вызов wait() на объект A и notify() на объект B не имеет смысла.
13

Допустим, у вас есть приложение «черный ящик» с какой-то класс с именем BlackBoxClass, который имеет метод doSomething();.

Кроме того, у вас есть наблюдатель или слушатель с именем onResponse(String resp), который будет вызван BlackBoxClass после неизвестного времени.

Поток прост:

private String mResponse = null; 
... 
BlackBoxClass bbc = new BlackBoxClass(); 
    bbc.doSomething(); 
... 
@override 
public void onResponse(String resp){   
     mResponse = resp;  
} 

Допустим, мы не знаем, что происходит с BlackBoxClass и когда мы должны получить ответ, но вы не хотите, чтобы продолжить свой код, пока вы получите ответ или другими словами получите onResponse звонок. Сюда входит «помощник Синхронизировать»:

public class SyncronizeObj { 
public void doWait(long l){ 
    synchronized(this){ 
     try { 
      this.wait(l); 
     } catch(InterruptedException e) { 
     } 
    } 
} 

public void doNotify() { 
    synchronized(this) { 
     this.notify(); 
    } 
} 

public void doWait() { 
    synchronized(this){ 
     try { 
      this.wait(); 
     } catch(InterruptedException e) { 
     } 
    } 
} 
} 

Теперь мы можем реализовать то, что мы хотим:

public class Demo { 

private String mResponse = null; 
... 
SyncronizeObj sync = new SyncronizeObj(); 

public void impl(){ 

BlackBoxClass bbc = new BlackBoxClass(); 
    bbc.doSomething(); 

    if(mResponse == null){ 
     sync.doWait(); 
    } 

/** at this momoent you sure that you got response from BlackBoxClass because 
    onResponse method released your 'wait'. In other cases if you don't want wait too  
    long (for example wait data from socket) you can use doWait(time) 
*/ 
... 

} 


@override 
public void onResponse(String resp){   
     mResponse = resp; 
     sync.doNotify();  
    } 

} 
0

Для этой конкретной проблемы, почему бы не хранить ваши различные результаты в переменных, а затем, когда последний из вашего поток обрабатывается, вы можете печатать в любом формате. Это особенно полезно, если вы собираетесь использовать свою историю работы в других проектах.

0

Это выглядит как ситуация для шаблона производителя-потребителя. Если вы используете java 5 или выше, вы можете использовать блокирующую очередь (java.util.concurrent.BlockingQueue) и оставить работу по координации потоков с базовой реализацией framework/api. Смотрите пример из Java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html или Java 7 (тот же пример): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

3

я право простой пример покажет вам, как правильно использовать wait и notify в Java. Итак, я создам два класса с именем ThreadA & ThreadB. ThreadA вызовет ThreadB.

public class ThreadA { 
    public static void main(String[] args){ 
     ThreadB b = new ThreadB();//<----Create Instance for seconde class 
     b.start();//<--------------------Launch thread 

     synchronized(b){ 
      try{ 
       System.out.println("Waiting for b to complete..."); 
       b.wait();//<-------------WAIT until the finish thread for class B finish 
      }catch(InterruptedException e){ 
       e.printStackTrace(); 
      } 

      System.out.println("Total is: " + b.total); 
     } 
    } 
} 

и для класса ThreadB:

class ThreadB extends Thread{ 
    int total; 
    @Override 
    public void run(){ 
     synchronized(this){ 
      for(int i=0; i<100 ; i++){ 
       total += i; 
      } 
      notify();//<----------------Notify the class wich wait until my finish 
//and tell that I'm finish 
      } 
     } 
    } 
2

мы можем назвать уведомит возобновить выполнение ожидающих объектов, как

public synchronized void guardedJoy() { 
    // This guard only loops once for each special event, which may not 
    // be the event we're waiting for. 
    while(!joy) { 
     try { 
      wait(); 
     } catch (InterruptedException e) {} 
    } 
    System.out.println("Joy and efficiency have been achieved!"); 
} 

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

public synchronized notifyJoy() { 
    joy = true; 
    notifyAll(); 
} 
0

Вы правильно охраняли свой кодовый блок, когда вы вызываете метод wait(), используя synchronized(this).

Но вы не приняли же меры предосторожности при вызове notify() метода без использования охраняемого блока: synchronized(this) или synchronized(someObject)

Если вы обратитесь к странице документации оракула на Object классе, который содержит wait(), notify(), notifyAll() методы, вы можете см ниже меры предосторожности во всех этих трех методов

Этот метод должен вызываться только потоком, который является владельцем монитора данного объекта

Многое изменилось за последние 7 лет, и давайте посмотрим на другие альтернативы synchronized в ниже SE вопросы:

Why use a ReentrantLock if one can use synchronized(this)?

Synchronization vs Lock

Avoid synchronized(this) in Java?

1

Простое использование, если вы хотите Как выполнить потоки в качестве альтернативы: -

public class MyThread { 
    public static void main(String[] args) { 
     final Object lock = new Object(); 
     new Thread(() -> { 
      try { 
       synchronized (lock) { 
        for (int i = 0; i <= 5; i++) { 
         System.out.println(Thread.currentThread().getName() + ":" + "A"); 
         lock.notify(); 
         lock.wait(); 
        } 
       } 
      } catch (Exception e) {} 
     }, "T1").start(); 

     new Thread(() -> { 
      try { 
       synchronized (lock) { 
        for (int i = 0; i <= 5; i++) { 
         System.out.println(Thread.currentThread().getName() + ":" + "B"); 
         lock.notify(); 
         lock.wait(); 
        } 
       } 
      } catch (Exception e) {} 
     }, "T2").start(); 
    } 
} 

Быстродействие: -

T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 

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

  • Нет связанных вопросов^_^