2009-05-20 12 views
120

Tengo 2 matrices y necesito multiplicarlas y luego imprimir los resultados de cada celda. Tan pronto como una celda esté lista, necesito imprimirla, pero por ejemplo necesito imprimir la celda [0] [0] antes de la celda [2] [0] incluso si el resultado de [2] [0] está listo primero . Entonces necesito imprimirlo por orden. Así que mi idea es hacer que la espera hasta que el hilo de la impresora multiplyThread le notifica que la célula correcta está listo para ser impreso y luego el printerThread imprimirá la célula y volver a esperar y así sucesivamente ..¿Cómo usar wait and notify en Java?

Así que tengo este thread que realiza la multiplicació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(); 
} 

hilo que imprime el resultado de cada celda:

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

Ahora me tiros estas excepciones:

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) 

línea 49 en multiplyThread es el "notify()" .. Creo que necesito utilizar el sincronizado de manera diferente, pero no estoy seguro de cómo.

Si alguien puede ayudar a que este código funcione, realmente lo agradeceré.

Respuesta

203

Para poder llamar notify() necesita sincronizar sobre el mismo objeto.

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

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

Esto es más rápido que los bloqueos personalizados, como while (otherThread.notReady) {}? ¿O más lento? –

+26

La opción 'while (! JobCompleted);' es generalmente una mala idea porque ata su CPU al 100% comprobando constantemente la misma variable (vea [aquí] (http://stackoverflow.com/a/1676030/57508)) –

+5

'while (! JobCompleted) Thread.sleep (5); 'no tiene ese problema – BeniBela

6

notify() necesita ser sincronizado, así

+0

:-) claro y directo al grano - saludos! – Premraj

7

Solo puede llamar a notificar sobre los objetos donde es propietario de su monitor. Entonces necesita algo como

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

¿Necesita enhebrar esto en absoluto? Me pregunto qué tan grande son tus matrices, y si hay algún beneficio en tener una impresión de hilo mientras que la otra multiplica.

Tal vez sería útil medir esta vez antes de realizar el trabajo de roscado relativamente complejo?

Si es necesario enhebrar ella, me gustaría crear 'n' hilos para llevar a cabo la multiplicación de las células (tal vez 'n' es el número de núcleos disponibles para usted), y luego utilizar el mecanismo de ExecutorService y Future a despacha múltiples multiplicaciones simultáneamente.

De esta manera puede optimizar el trabajo en función del número de núcleos, y está utilizando las herramientas de subprocesamiento de Java de nivel superior (que deberían facilitar la vida). Escriba los resultados de nuevo en una matriz receptora, y luego simplemente imprima esto una vez que todas sus tareas Futuras se hayan completado.

+1

+1 @Greg Creo que deberías echarle un vistazo al paquete java.util.concurrent, como señaló Brian. – ATorras

+1

+1 y también echa un vistazo a este libro que también le enseñará la forma correcta de usar wait() y notify() http://jcip.net/ – Chii

+0

Downvoted ¿por qué? –

62

Durante el uso de los wait y notify o notifyAll métodos en Java las siguientes cosas se deben tener:

  1. Uso notifyAll en lugar de notify si espera que más de un hilo estará esperando por una cerradura.
  2. The wait and notify methods must be called in a synchronized context. Vea el enlace para una explicación más detallada.
  3. Siempre llame al método wait() en un bucle porque si hay varios subprocesos esperando un bloqueo y uno de ellos obtuvo el bloqueo y restableció la condición, entonces los otros subprocesos deben verificar la condición después de que se despiertan para ver si necesitan esperar nuevamente o puede comenzar a procesar.
  4. Utilice el mismo objeto para llamar al método wait() y notify(); cada objeto tiene su propio candado, por lo que llamar al wait() en el objeto A y notify() en el objeto B no tendrá ningún sentido.
13

Digamos que usted tiene aplicación 'cuadro negro' con alguna clase llamada BlackBoxClass que tiene método doSomething();.

Además, tiene un observador u oyente llamado onResponse(String resp) que será llamado por BlackBoxClass después de la hora desconocida.

El flujo es simple:

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

digamos que no sabemos lo que está pasando con BlackBoxClass y cuando deberíamos obtener respuesta, pero que no quieren seguir con el código hasta que se obtiene respuesta o en otras palabras, obtenga onResponse llamada. Aquí entra 'Sincronizar ayudante':

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

Ahora podemos poner en práctica lo que queremos:

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

Para este problema en particular, por qué no almacenar hasta sus diversos resultados en las variables y luego, cuando el último de su el hilo se procesa, puede imprimir en el formato que desee. Esto es especialmente útil si va a utilizar su historial de trabajo en otros proyectos.

0

Esto parece una situación para el patrón productor-consumidor. Si usa Java 5 o superior, puede considerar el uso de la cola de bloqueo (java.util.concurrent.BlockingQueue) y dejar el trabajo de coordinación de subprocesos en la implementación de framework/api subyacente. Vea el ejemplo de Java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html o java 7 (mismo ejemplo): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

3

Voy a la derecha sencillo ejemplo a mostrar la manera correcta de utilizar wait y notify en Java. Así que crearé dos clases llamadas ThreadA & ThreadB. ThreadA llamará a 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); 
     } 
    } 
} 

y para la clase 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

podemos llamar a notificar a reanudar la ejecución de objetos de espera como

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

curriculum vitae este invocando notificar en otro objeto de la misma clase

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

Ha guardado correctamente su bloque de código cuando llama al método wait() utilizando synchronized(this).

Pero usted no ha tomado misma precaución cuando se llama notify() método sin utilizar el bloque vigilado: synchronized(this) o synchronized(someObject)

Si se refiere a la página de documentación de Oracle en Object clase, que contiene wait(), notify(), notifyAll() métodos, puede véase más adelante precaución en todos estos tres métodos

este método sólo debe ser llamado por un hilo que es el dueño de pantalla de este objeto

Muchas cosas han cambiado en los últimos 7 años y tengamos considerar otras alternativas a synchronized por debajo de las preguntas SE:

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

Synchronization vs Lock

Avoid synchronized(this) in Java?

1

uso simple si Desea Cómo ejecutar hilos alternativamente: -

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