¿Cómo usar esperar y notificar en Java sin IllegalMonitorStateException?

Resuelto asked hace 15 años • 12 respuestas

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 pedido. Entonces, mi idea es hacer que el hilo de la impresora espere hasta que le multiplyThreadnotifique que la celda correcta está lista para imprimirse y luego imprimirá printerThreadla celda y volverá a esperar y así sucesivamente.

Entonces tengo este hilo que hace 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 tira 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)

La línea 49 multiplyThreades "notificar()". Creo que necesito usar sincronizado de manera diferente, pero no estoy seguro de cómo.

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

 avatar May 20 '09 15:05
Aceptado

Para poder llamar a notify() necesitas sincronizar en el mismo objeto.

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

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}
Bombe avatar May 20 '2009 08:05 Bombe

Al utilizar los métodos waity notifyo notifyAllen Java se deben recordar las siguientes cosas:

  1. Úselo notifyAllen lugar de notifysi espera que más de un subproceso esté esperando un bloqueo.
  2. Los métodos waity notifydeben llamarse en un contexto sincronizado . Consulte el enlace para obtener una explicación más detallada.
  3. Siempre llame al wait()método en un bucle porque si varios subprocesos están 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 despertarse para ver si necesitan esperar nuevamente o puede comenzar a procesar.
  4. Utilice el mismo objeto para llamar wait()y notify()método; cada objeto tiene su propio bloqueo, por lo que llamar wait()al objeto A y notify()al objeto B no tendrá ningún sentido.
Jackob avatar Jun 03 '2011 00:06 Jackob

¿Necesitas enhebrar esto? Me pregunto qué tan grandes son sus matrices y si hay algún beneficio en tener un hilo impreso mientras el otro realiza la multiplicación.

¿Quizás valdría la pena medir este tiempo antes de realizar el trabajo de enhebrado relativamente complejo?

Si necesita enhebrarlo, crearía 'n' subprocesos para realizar la multiplicación de las celdas (quizás 'n' sea la cantidad de núcleos disponibles para usted) y luego usaría el mecanismo ExecutorService y Future para enviar múltiples multiplicaciones simultáneamente. .

De esa manera, puede optimizar el trabajo en función de la cantidad de núcleos y estará utilizando las herramientas de subprocesamiento de Java de nivel superior (que deberían hacer la vida más fácil). Vuelva a escribir los resultados en una matriz de recepción y luego simplemente imprímala una vez que se hayan completado todas sus tareas futuras.

Brian Agnew avatar May 20 '2009 08:05 Brian Agnew