如何在没有 IllegalMonitorStateException 的情况下在 Java 中使用等待和通知?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/886722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:40:39  来源:igfitidea点击:

How to use wait and notify in Java without IllegalMonitorStateException?

javamultithreadingexceptionjava-threads

提问by

I have 2 matrices and I need to multiply them and then print the results of each cell. As soon as one cell is ready I need to print it, but for example I need to print the [0][0] cell before cell [2][0] even if the result of [2][0] is ready first. So I need to print it by order. So my idea is to make the printer thread wait until the multiplyThreadnotifies it that the correct cell is ready to be printed and then the printerThreadwill print the cell and go back to waiting and so on..

我有 2 个矩阵,我需要将它们相乘,然后打印每个单元格的结果。一个单元格准备好后,我需要打印它,但例如,即使 [2][0] 的结果已准备好,我也需要在单元格 [2][0] 之前打印 [0][0] 单元格. 所以我需要按顺序打印它。所以我的想法是让打印机线程等待,直到multiplyThread通知它正确的单元格已准备好打印,然后printerThread将打印单元格并返回等待等等。

So I have this thread that does the multiplication:

所以我有这个线程来做乘法:

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

Thread that prints the result of each cell:

打印每个单元格结果的线程:

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

Now it throws me these exceptions:

现在它向我抛出这些异常:

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)

line 49 in multiplyThreadis the "notify()"..I think I need to use the synchronized differently but I am not sure how.

第 49 行multiplyThread是“notify()”……我想我需要以不同的方式使用同步,但我不确定如何使用。

If anyone can help this code to work I will really appreciate it.

如果有人可以帮助此代码工作,我将非常感激。

采纳答案by Bombe

To be able to call notify()you need to synchronize on the same object.

为了能够调用notify(),您需要在同一个对象上进行同步。

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

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

回答by takete.dk

notify()needs to be synchronized as well

notify()也需要同步

回答by PaulJWilliams

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

您只能在拥有监视器的对象上调用通知。所以你需要类似的东西

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

回答by Brian Agnew

Do you need to thread this at all ? I'm wondering how big your matrices are, and whether there's any benefit in having one thread print whilst the other does the multiplication.

你需要穿这个吗?我想知道您的矩阵有多大,以及让一个线程打印而另一个线程进行乘法是否有任何好处。

Perhaps it would be worth measuring this time before doing the relatively complex threading work ?

也许在进行相对复杂的线程工作之前,这次值得测量一下?

If you do need to thread it, I would create 'n' threads to perform the multiplication of the cells (perhaps 'n' is the number of cores available to you), and then use the ExecutorServiceand Futuremechanism to dispatch multiple multiplications simultaneously.

如果您确实需要线程化,我将创建“n”个线程来执行单元格的乘法(也许“n”是您可用的内核数),然后使用ExecutorServiceFuture机制同时调度多个乘法.

That way you can optimise the work based on the number of cores, and you're using the higher level Java threading tools (which should make life easier). Write the results back into a receiving matrix, and then simply print this once all your Future tasks have completed.

这样您就可以根据内核数量优化工作,并且您正在使用更高级别的 Java 线程工具(这应该会让生活更轻松)。将结果写回接收矩阵,然后在所有未来任务完成后简单地打印出来。

回答by Hymanob

While using the waitand notifyor notifyAllmethods in Java the following things must be remembered:

在 Java 中使用waitandnotifynotifyAll方法时,必须记住以下几点:

  1. Use notifyAllinstead of notifyif you expect that more than one thread will be waiting for a lock.
  2. The waitand notifymethods must be called in a synchronized context. See the link for a more detailed explanation.
  3. Always call the wait()method in a loop because if multiple threads are waiting for a lock and one of them got the lock and reset the condition, then the other threads need to check the condition after they wake up to see whether they need to wait again or can start processing.
  4. Use the same object for calling wait()and notify()method; every object has its own lock so calling wait()on object A and notify()on object B will not make any sense.
  1. 如果您期望多个线程等待锁定,请使用notifyAll代替notify
  2. waitnotify方法必须在同步上下文中调用。有关更详细的解释,请参阅链接。
  3. 总是wait()在循环中调用该方法,因为如果多个线程正在等待一个锁并且其中一个线程获得了锁并重置了条件,那么其他线程需要在它们醒来后检查条件以查看是否需要再次等待或可以开始处理了。
  4. 调用wait()notify()方法使用同一个对象;每个对象都有自己的锁,因此调用wait()对象 A 和notify()对象 B 没有任何意义。

回答by Maxim Shoustin

Let's say you have 'black box' application with some class named BlackBoxClassthat has method doSomething();.

假设您有一个“黑匣子”应用程序,其中包含一些名为BlackBoxClassmethod 的类doSomething();

Further, you have observer or listener named onResponse(String resp)that will be called by BlackBoxClassafter unknown time.

此外,您有命名的观察者或侦听器onResponse(String resp),它们将BlackBoxClass在未知时间之后被调用。

The flow is simple:

流程很简单:

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

Lets say we don't know what is going on with BlackBoxClassand when we should get answer but you don't want to continue your code till you get answer or in other word get onResponsecall. Here enters 'Synchronize helper':

假设我们不知道发生了什么BlackBoxClass以及何时应该得到答案,但您不想继续您的代码,直到您得到答案或换句话说就是onResponse接到电话。这里输入“同步助手”:

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) {
        }
    }
}
}

Now we can implement what we want:

现在我们可以实现我们想要的:

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

}

回答by kbluue

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.

对于这个特定问题,为什么不将各种结果存储在变量中,然后在处理最后一个线程时,您可以以任何您想要的格式打印。如果您要在其他项目中使用您的工作历史,这将特别有用。

回答by user3044236

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.htmlor java 7 (same example): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

这看起来像是生产者-消费者模式的一种情况。如果您使用的是 java 5 或更高版本,您可以考虑使用阻塞队列(java.util.concurrent.BlockingQueue)并将线程协调工作留给底层框架/api 实现。请参阅 java 5 中的 示例:http: //docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html或 java 7(相同示例): http://docs。 oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

回答by BERGUIGA Mohamed Amine

I'll right simple example show you the right way to use waitand notifyin Java. So I'll create two class named ThreadA& ThreadB. ThreadA will call ThreadB.

我将正确的简单示例向您展示在 Java 中使用wait和使用的正确方法notify。所以我将创建两个名为ThreadAThreadB 的类。线程A 将调用线程B。

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:

对于 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
            }
        }
    }

回答by Greesh Kumar

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

我们可以调用notify来恢复等待对象的执行

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