2009-05-20 16 views
120

Ho 2 matrici e ho bisogno di moltiplicarle e quindi stampare i risultati di ogni cella. Non appena una cella è pronta, devo stamparla, ma per esempio devo stampare la cella [0] [0] prima della cella [2] [0] anche se il risultato di [2] [0] è pronto prima . Quindi ho bisogno di stamparlo per ordine. Quindi la mia idea è quella di rendere l'attesa fino a quando il filo della stampante multiplyThread di informarla che la cella corretta è pronto per essere stampato e poi il printerThread stampa il cellulare e tornare in attesa e così via ..Come utilizzare wait e notify in Java?

Quindi devo questa discussione che fa la moltiplicazione:

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

filo che stampa il risultato di ogni cella:

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

Ora mi tiri queste eccezioni:

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) 

riga 49 in multiplyThread è il "notify()" .. Penso che ho bisogno di utilizzare il sincronizzato in modo diverso, ma non sono sicuro di come.

Se qualcuno può aiutare questo codice a funzionare lo apprezzerò molto.

risposta

203

Per essere in grado di chiamare notify() è necessario sincronizzare sullo stesso oggetto.

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

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

Questo è più veloce dei blocchi personalizzati come while (otherThread.notReady) {}? O più lento? –

+26

L'opzione 'while (! JobCompleted);' è generalmente una cattiva idea perché lega la tua CPU al 100% controllando costantemente la stessa variabile (vedi [qui] (http://stackoverflow.com/a/1676030/57508)) –

+5

'while (! JobCompleted) Thread.sleep (5); 'non ha quel problema – BeniBela

6

notify() deve essere sincronizzato così

+0

:-) chiaro e dritto al punto - evviva! – Premraj

7

È possibile chiamare solo la notifica sugli oggetti in cui si possiede il proprio monitor. Quindi avete bisogno di qualcosa come

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

Avete bisogno di infilarlo a tutti? Mi chiedo quanto sono grandi le matrici e se ci sono dei vantaggi nell'avere una stampa di thread mentre l'altra fa la moltiplicazione.

Forse sarebbe opportuno misurare questa volta prima di eseguire il lavoro di threading relativamente complesso?

Se è necessario eseguirne il thread, creo 'n' thread per eseguire la moltiplicazione delle celle (forse 'n' è il numero di core disponibili), quindi utilizzare il meccanismo ExecutorService e Future per inviare più moltiplicazioni contemporaneamente.

In questo modo è possibile ottimizzare il lavoro in base al numero di core e si utilizzano gli strumenti di threading Java di livello superiore (che dovrebbero semplificare la vita). Scrivi nuovamente i risultati in una matrice di ricezione, quindi stampalo una volta completate tutte le attività future.

+1

+1 @Greg Penso che dovresti dare un'occhiata al pacchetto java.util.concurrent, come sottolineato da Brian. – ATorras

+1

+1 e controlla anche questo libro che ti indicherà anche il modo corretto di usare wait() e notify() http://jcip.net/ – Chii

+0

Downvoted perché? –

62

Durante l'utilizzo i wait e notify o notifyAll metodi in Java le seguenti cose devono essere ricordate:

  1. Uso notifyAll invece di notify se ci si aspetta che più di un thread sarà in attesa di un blocco.
  2. The wait and notify methods must be called in a synchronized context. Vedi il link per una spiegazione più dettagliata.
  3. Chiamare sempre il metodo wait() in un ciclo perché se più thread sono in attesa di un blocco e uno di loro ha il blocco e ripristina la condizione, gli altri thread devono controllare le condizioni dopo che si sono svegliati per vedere se hanno bisogno di attendere ancora o iniziare l'elaborazione.
  4. Utilizzare lo stesso oggetto per chiamare il metodo wait() e notify(); ogni oggetto ha il proprio blocco, quindi chiamare wait() sull'oggetto A e notify() sull'oggetto B non ha alcun senso.
13

Diciamo che avete applicazione 'scatola nera' con una certa classe denominata BlackBoxClass che ha metodo doSomething();.

Inoltre, si ha osservatore o ascoltatore chiamato onResponse(String resp) che verrà chiamato da BlackBoxClass dopo un orario sconosciuto.

Il flusso è semplice:

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

Diciamo che non sappiamo cosa sta succedendo con BlackBoxClass e quando dovremmo ottenere risposta, ma non si vuole continuare il tuo codice fino ad ottenere risposta o in altre parole chiama onResponse. Qui entra 'Sincronizza aiutante':

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

Ora possiamo realizzare ciò che vogliamo:

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

Per questo particolare problema, perché non memorizzare i vostri vari risultati nelle variabili e poi, quando l'ultimo della vostra il thread è processato puoi stampare in qualsiasi formato tu voglia. Questo è particolarmente utile se utilizzerai la tua cronologia di lavoro in altri progetti.

0

Sembra una situazione per il modello produttore-consumatore. Se si utilizza java 5 o versioni successive, è possibile considerare l'utilizzo della coda di blocco (java.util.concurrent.BlockingQueue) e lasciare il lavoro di coordinamento del thread all'implementazione framework/api sottostante. Vedere l'esempio da Java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html o Java 7 (stesso esempio): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

3

sarò giusto semplice esempio ti mostri il modo giusto di usare wait e notify in Java. Quindi creerò due classi denominate ThreadA & ThreadB. ThreadA chiamerà 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); 
     } 
    } 
} 

e per la Classe 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

possiamo chiamare notifica di riprendere l'esecuzione di oggetti in attesa come

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

riprendere questo invocando notifica su un altro oggetto della stessa classe

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

Hai protetto correttamente il tuo blocco di codice quando chiami il metodo wait() utilizzando synchronized(this).

Ma voi non avete preso stessa precauzione quando si chiama notify() metodo senza l'utilizzo di blocco sorvegliato: synchronized(this) o synchronized(someObject)

Se si fa riferimento alla pagina di documentazione Oracle su Object di classe, che contiene wait(), notify(), notifyAll() metodi, è possibile vedere qui precauzione in tutti questi tre metodi

questo metodo deve essere chiamato solo da un filo che è il proprietario del monitor di questa oggetto

0.123.516,410617 millions

Molte cose sono cambiate negli ultimi 7 anni e diamo un'occhiata in altre alternative per synchronized in seguito domande SE:

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

Synchronization vs Lock

Avoid synchronized(this) in Java?

1

uso semplice se vuoi come eseguire thread in alternativa: -

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

responce: -

T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
T1:A 
T2:B 
Problemi correlati