2009-05-20 43 views
120

Tôi có 2 ma trận và tôi cần nhân chúng và sau đó in kết quả của mỗi ô. Ngay sau khi một ô đã sẵn sàng, tôi cần in nó, nhưng ví dụ tôi cần in ô [0] [0] trước ô [2] [0] ngay cả khi kết quả của [2] [0] đã sẵn sàng trước . Vì vậy, tôi cần phải in nó theo thứ tự. Vì vậy, ý tưởng của tôi là làm cho sự chờ đợi chủ đề máy in cho đến khi multiplyThread thông báo đó mà các tế bào đúng là đã sẵn sàng để được in và sau đó là printerThread sẽ in các tế bào và quay trở lại chờ đợi và vân vân ..Cách sử dụng chờ và thông báo bằng Java?

Vì vậy, tôi có chủ đề này mà không được phép nhân:

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(); 
} 

chủ đề đó in kết quả của mỗi tế bào:

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] + " "); 
      } 
     } 
    } 

Bây giờ nó ném cho tôi những trường hợp ngoại lệ:

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) 

dòng 49 trong multiplyThread là "thông báo()" .. Tôi nghĩ rằng tôi cần phải sử dụng đồng bộ hóa khác nhau nhưng tôi không chắc chắn như thế nào.

Nếu có ai đó có thể giúp mã này hoạt động, tôi thực sự sẽ đánh giá cao nó.

Trả lời

203

Để có thể gọi notify() bạn cần phải đồng bộ hóa trên cùng một đối tượng.

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

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

Điều này nhanh hơn khóa tùy chỉnh, chẳng hạn như while (otherThread.notReady) {}? Hoặc chậm hơn? –

+26

Tùy chọn 'while (! JobCompleted);' thường là một ý tưởng tồi vì nó liên kết CPU của bạn ở mức 100% kiểm tra cùng một biến liên tục (xem [ở đây] (http://stackoverflow.com/a/1676030/57508)) –

+5

'while (! JobCompleted) Thread.sleep (5); 'không có vấn đề đó – BeniBela

6

notify() cần phải được đồng bộ cũng

+0

:-) rõ ràng và thẳng vào vấn đề - chúc mừng! – Premraj

7

Bạn chỉ có thể gọi thông báo cho các đối tượng nơi bạn sở hữu màn hình của họ. Vì vậy, bạn cần một cái gì đó như

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

Bạn có cần chỉ định luồng này không? Tôi tự hỏi làm thế nào lớn ma trận của bạn, và cho dù có bất kỳ lợi ích trong việc có một sợi in trong khi khác không nhân.

Có lẽ sẽ đáng để đo thời gian này trước khi thực hiện công việc luồng tương đối phức tạp?

Nếu bạn cần tạo chuỗi, tôi sẽ tạo chủ đề 'n' để nhân các ô (có lẽ 'n' là số lõi có sẵn cho bạn), và sau đó sử dụng cơ chế ExecutorServiceFuture gửi nhiều phép nhân cùng một lúc.

Bằng cách đó bạn có thể tối ưu hóa công việc dựa trên số lượng lõi và bạn đang sử dụng các công cụ luồng Java cao hơn (điều này sẽ giúp cuộc sống dễ dàng hơn). Viết kết quả trở lại vào ma trận nhận, và sau đó chỉ cần in này một khi tất cả các nhiệm vụ trong tương lai của bạn đã hoàn thành.

+1

+1 @Greg Tôi nghĩ bạn nên xem gói java.util.concurrent, như được Brian chỉ ra. – ATorras

+1

+1 và cũng kiểm tra cuốn sách này cũng sẽ dạy cho bạn cách chính xác để sử dụng wait() và thông báo() http://jcip.net/ – Chii

+0

Downvoted tại sao? –

62

Trong khi sử dụng waitnotify hoặc notifyAll phương pháp trong Java những điều sau đây phải nhớ:

  1. Sử dụng notifyAll thay vì notify nếu bạn hy vọng rằng hơn một thread sẽ chờ đợi cho một khóa.
  2. The wait and notify methods must be called in a synchronized context. Xem liên kết để có giải thích chi tiết hơn.
  3. Luôn gọi phương thức wait() trong vòng lặp vì nếu nhiều chủ đề đang chờ khóa và một trong số chúng có khóa và đặt lại điều kiện, thì các chủ đề khác cần kiểm tra điều kiện sau khi thức dậy để xem liệu chúng có cần chờ một lần nữa hoặc có thể bắt đầu xử lý.
  4. Sử dụng cùng một đối tượng để gọi phương thức wait()notify(); mỗi đối tượng có khóa riêng của nó để gọi wait() trên đối tượng A và notify() trên đối tượng B sẽ không có ý nghĩa gì.
13

Giả sử bạn có ứng dụng 'hộp đen' với một số lớp có tên là BlackBoxClass có phương thức doSomething();.

Hơn nữa, bạn có người quan sát hoặc người nghe có tên onResponse(String resp) sẽ được gọi theo số BlackBoxClass sau thời gian không xác định.

Dòng chảy rất đơn giản:

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

phép nói rằng chúng ta không biết những gì đang xảy ra với BlackBoxClass và khi chúng ta sẽ nhận được câu trả lời nhưng bạn không muốn tiếp tục mã của bạn cho đến khi bạn có được câu trả lời hay nói cách khác, hãy gọi số onResponse. Đây nhập 'Đồng bộ hóa helper':

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) { 
     } 
    } 
} 
} 

Bây giờ chúng ta có thể thực hiện những gì chúng ta muốn:

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

Đối với vấn đề cụ thể này, tại sao không lưu trữ các kết quả khác nhau của bạn trong các biến và sau đó khi người cuối cùng của bạn thread được xử lý, bạn có thể in ở bất kỳ định dạng nào bạn muốn. Điều này đặc biệt hữu ích nếu bạn đang sử dụng lịch sử công việc của mình trong các dự án khác.

0

Điều này giống như một tình huống cho mô hình người tiêu dùng sản xuất. Nếu bạn đang sử dụng java 5 trở lên, bạn có thể xem xét việc sử dụng hàng đợi chặn (java.util.concurrent.BlockingQueue) và để công việc phối hợp luồng thực hiện khung công tác/api cơ bản. Xem ví dụ từ java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html hoặc java 7 (giống ví dụ): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

3

tôi sẽ ví dụ đúng đơn giản chỉ cho bạn đúng cách để sử dụng waitnotify trong Java. Vì vậy, tôi sẽ tạo hai lớp có tên là ThreadA & ThreadB. ThreadA sẽ gọi 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); 
     } 
    } 
} 

và cho Class 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

chúng ta có thể gọi thông báo để tiếp tục thực hiện các đối tượng chờ đợi như

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!"); 
} 

resume này bằng cách gọi thông báo về một đối tượng của cùng một lớp

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

Bạn đã bảo vệ đúng khối mã của mình khi bạn gọi phương thức wait() bằng cách sử dụng synchronized(this).

Nhưng bạn đã không được thực hiện cùng một biện pháp phòng ngừa khi bạn gọi notify() phương pháp mà không sử dụng khối bảo vệ: synchronized(this) hoặc synchronized(someObject)

Nếu bạn tham khảo trang tài liệu oracle trên Object lớp, trong đó có wait(), notify(), notifyAll() phương pháp, bạn có thể xem dưới đây phòng ngừa trong tất cả ba phương pháp này

Phương pháp này chỉ nên được gọi bởi chủ sở hữu của màn hình của đối tượng này

Nhiều việc đã được thay đổi trong vòng 7 năm qua và chúng ta hãy có cái nhìn vào lựa chọn thay thế khác để synchronized ở bên dưới câu hỏi SE:

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

Synchronization vs Lock

Avoid synchronized(this) in Java?

1

sử dụng đơn giản nếu bạn muốn Cách thực hiện các chủ đề khác: -

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(); 
    } 
} 

phản ứng: -

T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
Các vấn đề liên quan