[java] IllegalMonitorStateException없이 Java에서 대기 및 알림을 사용하는 방법은 무엇입니까?

나는 2 개의 행렬을 가지고 있으며 그것들을 곱한 다음 각 셀의 결과를 인쇄해야합니다. 하나의 셀이 준비되면 바로 인쇄해야하지만, 예를 들어 [2] [0]의 결과가 먼저 준비된 경우에도 [2] [0] 셀 앞에 [0] [0] 셀을 인쇄해야합니다 . 순서대로 인쇄해야합니다. 그래서 내 생각은 multiplyThread올바른 셀을 인쇄 할 준비가되었다는 알림을 받을 때까지 프린터 스레드를 기다리게 printerThread하고 셀을 인쇄하고 대기 등으로 돌아가는 것입니다.

그래서 곱셈을하는이 스레드가 있습니다.

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

각 셀의 결과를 인쇄하는 스레드 :

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

이제 다음과 같은 예외가 발생합니다.

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)

49 줄 multiplyThread은 “notify ()”입니다. 동기화를 다르게 사용해야하지만 어떻게 해야할지 잘 모르겠습니다.

누구나이 코드가 작동하도록 도울 수 있다면 정말 감사하겠습니다.



답변

notify () 를 호출하려면 동일한 객체에서 동기화해야합니다.

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

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


답변

Java에서 waitand notify또는 notifyAll메소드를 사용하는 동안 다음 사항을 기억해야합니다.

  1. 둘 이상의 스레드가 잠금을 대기 할 것으로 예상되는 경우 notifyAll대신 사용하십시오 notify.
  2. waitnotify방법은 동기화 된 컨텍스트에서 호출되어야합니다 . 자세한 설명은 링크를 참조하십시오.
  3. wait()여러 스레드가 잠금을 기다리고 있고 그 중 하나가 잠금 상태가되어 조건을 재설정하는 경우 다른 스레드가 깨어 난 후 상태를 확인하여 다시 대기해야하는지 여부를 확인해야하기 때문에 항상 루프 에서 메소드를 호출 하십시오. 처리를 시작할 수 있습니다.
  4. 호출 wait()notify()메소드에 동일한 오브젝트를 사용하십시오 . 모든 객체에는 자체 잠금 기능이 있으므로 wait()객체 A와 notify()객체 B를 호출 해도 의미가 없습니다.

답변

이걸 전혀 쓰지 않아도 되나요? 행렬이 얼마나 큰지 궁금하고 하나의 스레드 인쇄가 다른 반면 곱셈을 수행하는 데 어떤 이점이 있는지 궁금합니다.

아마도 비교적 복잡한 스레딩 작업을 수행하기 전에 이번에 측정 할 가치가 있습니까?

스레드 해야하는 경우 셀의 곱셈을 수행하기 위해 ‘n’스레드를 만들고 ( ‘n’은 사용 가능한 코어 수입니다) ExecutorServiceFuture 메커니즘을 사용하여 여러 곱셈을 동시에 디스패치합니다 .

그렇게하면 코어 수를 기준으로 작업을 최적화 할 수 있으며 더 높은 수준의 Java 스레딩 도구를 사용하게됩니다 (삶을 더 편하게 만들어야 함). 결과를 다시 수신 행렬에 기록한 다음 모든 향후 작업이 완료되면 간단히 인쇄하십시오.


답변

BlackBoxClassmethod가 있는 클래스가있는 ‘black box’애플리케이션이 있다고 가정 해 봅시다 doSomething();.

또한 알 수없는 시간 onResponse(String resp)BlackBoxClass지나면 호출 될 관찰자 또는 청취자 가 있습니다 .

흐름은 간단합니다.

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

우리는 무슨 일이 일어나고 있는지 BlackBoxClass, 언제 답변을 받아야 하는지 알지 못하지만 답변을 얻거나 다른 말로 onResponse전화 를받을 때까지 코드를 계속하고 싶지 않다고 가정 해 봅시다 . 여기에 ‘Synchronize 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) {
        }
    }
}
}

이제 원하는 것을 구현할 수 있습니다 :

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

}


답변

모니터를 소유 한 개체에 대해서만 알림을 호출 할 수 있습니다. 그래서 당신은 같은 것이 필요합니다

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


답변

notify() 뿐만 아니라 동기화해야합니다


답변

나는 바로 간단한 예제를 사용하는 올바른 방법 보여주지 waitnotify자바를. ThreadA & ThreadB 라는 두 클래스를 만들겠습니다 . ThreadA는 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);
        }
    }
} 

클래스 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
            }
        }
    }