Pergunta

Eu tenho 2 matrizes e eu preciso multiplicá-los e, em seguida, imprimir os resultados de cada célula. Assim que uma célula é que eu preciso pronto para imprimi-lo, mas, por exemplo, eu preciso imprimir o [0] [0] célula antes célula [2] [0], mesmo que o resultado de [2] [0] está pronto primeiro . Então eu preciso imprimi-lo por ordem. Assim, a minha ideia é fazer com que a espera fio da impressora até que os notifica multiplyThread de TI que a célula correta está pronto para ser impresso e, em seguida, o printerThread irá imprimir o celular e voltar a espera e assim por diante ..

Então, eu tenho esta discussão que faz a multiplicação:

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

linha que imprime o resultado de cada célula:

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

Agora, isto me lança as seguintes exceções:

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)

linha 49 em multiplyThread é o "notificar ()" .. Eu acho que eu preciso para usar o sincronizados de forma diferente, mas eu não sei como.

Se alguém puder ajudar este código para trabalhar eu realmente aprecio isso.

Foi útil?

Solução

Para ser capaz de chamada notificar () você precisa para sincronizar no mesmo objeto.

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

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

Outras dicas

Ao usar o wait e métodos notify ou notifyAll em Java as seguintes coisas devem ser lembradas:

  1. Use notifyAll vez de notify se você espera que mais de um thread estará esperando por um bloqueio.
  2. Os métodos wait e notify deve ser chamado num contexto sincronizado. Veja o link para uma explicação mais detalhada.
  3. Sempre chamar o método wait() em um loop porque se vários segmentos estão aguardando por uma trava e um deles tem a fechadura e repor a condição, então os outros tópicos precisa verificar a condição depois de acordar para ver se eles precisam que esperar novamente ou pode iniciar o processamento.
  4. Use o mesmo objeto para chamar wait() e método notify(); cada objeto tem seu próprio cadeado para chamar wait() em objeto A e notify() no objeto B não faz qualquer sentido.

Você precisa enfiar isso em tudo? Eu estou querendo saber o quão grande suas matrizes são, e se há algum benefício em ter um segmento de impressão, enquanto o outro faz a multiplicação.

Talvez valeria a pena medir este tempo antes de fazer o trabalho de segmentação relativamente complexa?

Se você precisa enfiar-lo, eu iria criar 'n' threads para executar a multiplicação das células (talvez 'n' é o número de núcleos disponíveis para você), e depois usar o ExecutorService e mecanismo Futuro para despachar várias multiplicações simultaneamente.

Dessa forma, você pode otimizar o trabalho com base no número de núcleos, e você estiver usando as ferramentas de threading nível Java mais elevados (o que deve tornar a vida mais fácil). Escreva os resultados de volta em uma matriz de recepção, e depois simplesmente imprimir desta vez todas as suas tarefas futuras tenham concluído.

Vamos dizer que você tem aplicativo 'caixa negra' com alguma classe BlackBoxClass nomeado que tem método doSomething();.

Além disso, você tem observador ou ouvinte chamado onResponse(String resp) que será chamado pelo BlackBoxClass após o tempo desconhecido.

O fluxo é simples:

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

Vamos dizer que nós não sabemos o que está acontecendo com BlackBoxClass e quando deve obter resposta, mas você não quer continuar o seu código até chegar resposta ou em outra chamada onResponse palavra get. Aqui entra 'Sincronizar 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) {
        }
    }
}
}

Agora podemos implementar o 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();       
   }

}

Você só pode chamar notificar em objetos onde possuem seu monitor. Então você precisa de algo como

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

necessidades notify() a serem sincronizados, bem

Eu vou certo exemplo simples mostrar-lhe o caminho certo para usar wait e notify em Java. Então, eu vou criar duas classes chamado ThreadA & ThreadB . ThreadA chamará 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 para a 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
            }
        }
    }

Podemos chamar notificar para retomar a execução de espera como objetos

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

retomar esta invocando notificar em um outro objeto da mesma classe

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

O uso simples se você quiser Como executar threads em 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();
    }
}

resposta: -

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 particular, porque não armazenar até seus vários resultados em variáveis ??e, em seguida, quando o último de seu segmento é processado você pode imprimir em qualquer formato desejado. Isto é especialmente útil se você estiver indo estar usando seu histórico de trabalho em outros projetos.

Isto parece uma situação para o padrão de produtor-consumidor. Se você estiver usando Java 5 ou para cima, você pode considerar o uso da fila de bloqueio (java.util.concurrent.BlockingQueue) e deixar o trabalho de coordenação linha para a implementação de estrutura / api subjacente. Veja o exemplo de java 5: http://docs.oracle.com /javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html ou java 7 (o mesmo exemplo): http://docs.oracle.com/javase /7/docs/api/java/util/concurrent/BlockingQueue.html

Você guardado adequadamente o seu bloco de código quando você chamar o método wait() usando synchronized(this).

Mas você não tomaram mesma precaução quando você chamar o método notify() sem o uso de bloco guardado: synchronized(this) ou synchronized(someObject)

Se você consultar a página de documentação do Oracle em Objeto classe , que contém wait(), notify(), métodos notifyAll(), você pode ver abaixo precaução em todos esses três métodos

Este método só deve ser chamado por um thread que é o proprietário do Monitor deste objeto

Muitas coisas foram alterados nos últimos 7 anos e vamos ter o olhar para outras alternativas para synchronized em abaixo perguntas SE:

Por que usar um ReentrantLock se se pode usar sincronizado (isso)?

sincronização vs bloqueio

Evite sincronizado (this) em Java?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top