Programing

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

lottogame 2020. 7. 4. 10:41
반응형

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 라는 클래스가있는 '블랙 박스'응용 프로그램이 있다고 가정 해 봅시다 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();       
   }

}

You can only call notify on objects where you own their monitor. So you need something like

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

notify() needs to be synchronized as well


I'll right simple example show you the right way to use wait and notify in Java. So I'll create two class named ThreadA & ThreadB. ThreadA will call 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);
        }
    }
} 

and for Class 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
            }
        }
    }

we can call notify to resume the execution of waiting objects as

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

resume this by invoking notify on another object of same class

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

Simple use if you want How to execute threads alternatively :-

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

response :-

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

For this particular problem, why not store up your various results in variables and then when the last of your thread is processed you can print in whatever format you want. This is especially useful if you are gonna be using your work history in other projects.


This looks like a situation for producer-consumer pattern. If you’re using java 5 or up, you may consider using blocking queue(java.util.concurrent.BlockingQueue) and leave the thread coordination work to the underlying framework/api implementation. See the example from java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html or java 7 (same example): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html


You have properly guarded your code block when you call wait() method by using synchronized(this).

But you have not taken same precaution when you call notify() method without using guarded block : synchronized(this) or synchronized(someObject)

If you refer to oracle documentation page on Object class, which contains wait() ,notify(), notifyAll() methods, you can see below precaution in all these three methods

This method should only be called by a thread that is the owner of this object's monitor

Many things have been changed in last 7 years and let's have look into other alternatives to synchronized in below SE questions:

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

Synchronization vs Lock

Avoid synchronized(this) in Java?

참고URL : https://stackoverflow.com/questions/886722/how-to-use-wait-and-notify-in-java-without-illegalmonitorstateexception

반응형