Pregunta

Tengo 2 matrices y necesito multiplicar ellos y luego imprimir los resultados de cada celda. Tan pronto como una célula está lista tengo que imprimirlo, pero por ejemplo que necesito para imprimir el [0] [0] celular antes de células [2] [0], incluso si el resultado de [2] [0] está listo primera . Así que tengo que 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 ..

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

Tema 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 arroja las siguientes 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 "notificar ()" .. Creo que necesito para usar la sincronizados de manera diferente pero no estoy seguro de cómo.

Si alguien puede ayudar a que este código funcione realmente voy a apreciarlo.

¿Fue útil?

Solución

Para ser capaz de llamar a notificar () necesita sincronizar sobre el mismo objeto.

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

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

Otros consejos

Durante el uso de la wait y métodos notify o notifyAll 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. Los métodos wait y notify debe ser llamado en un contexto sincronizada. Vea el enlace para una explicación más detallada.
  3. Siempre llamar al método wait() en un bucle porque si varios subprocesos están esperando un bloqueo y una de ellas tiene el bloqueo y restablecer la condición, entonces los otros hilos necesitan para comprobar el estado después de levantarse para ver si necesitan que esperar de nuevo o se puede iniciar el procesamiento.
  4. Utilice el mismo objeto para llamar wait() y el método notify(); cada objeto tiene su propia cerradura para llamar wait() en el objeto A y notify() en el objeto B no tendrá ningún sentido.

¿Es necesario enhebrar esto en absoluto? Me pregunto cómo es grande sus matrices son, y si no hay ningún beneficio en tener un hilo de impresión, mientras que el otro hace la multiplicación.

Tal vez sería interesante medir este tiempo antes de hacer el trabajo relativamente complejo rosca?

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 usar el ExecutorService y Future mecanismo para enviar múltiples multiplicaciones simultáneamente.

De esta manera se puede optimizar el trabajo basado en el número de núcleos, y está utilizando el nivel más alto de Java herramientas de roscar (que debería hacer la vida más fácil). Escribir los resultados de nuevo en una matriz que recibe, y luego simplemente imprimir esta vez todas sus tareas futuras han completado.

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

Además, usted tiene observador u oyente llamado onResponse(String resp) que será llamado por BlackBoxClass después de un tiempo desconocido.

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 no desea continuar su código hasta que se obtiene respuesta, o en otras palabras obtener 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();       
   }

}

Sólo puede llamar a notificar sobre los objetos sobre los que posees su monitor. Así que hay algo así como

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

notify() necesita ser sincronizado así

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

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

reanudar esta invocando notificar en otro objeto de la misma clase

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

Un uso correcto si quieres la forma de ejecutar las discusiones 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();
    }
}
  

Respuesta: -

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

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

Esto parece ser una situación para el patrón de productor-consumidor. Si está utilizando Java 5 o hacia arriba, se puede considerar el uso de colas de bloqueo (java.util.concurrent.BlockingQueue) y dejar el trabajo de coordinación de roscas en el marco de implementación / 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 (el mismo ejemplo): http://docs.oracle.com/javase /7/docs/api/java/util/concurrent/BlockingQueue.html

Se ha guardado correctamente el bloque de código cuando se llama método wait() utilizando synchronized(this).

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

Si se hace referencia a la página de documentación de Oracle en href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html" clase, que contiene wait(), notify(), métodos notifyAll(), se puede ver a continuación 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:

Por qué utilizar un ReentrantLock si se puede utilice sincronizada (esto)?

sincronización vs Bloqueo

Evitar sincronizado (este) en Java?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top