如何在Java中使用等待和通知?

时间:2021-04-23 17:35:51

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 multiplyThread notifies it that the correct cell is ready to be printed and then the printerThread will print the cell and go back to waiting and so on..

我有两个矩阵,我需要把它们相乘然后打印出每个单元格的结果。一旦一个单元格准备好了,我就需要打印它,但是例如,我需要在单元格[2][0]之前打印[0],即使[2][0]的结果首先准备好。所以我需要按顺序打印。所以我的想法是让打印机线程等待,直到多线程通知它正确的单元格已经准备好打印,然后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 multiplyThread is the "notify()"..I think I need to use the synchronized differently but I am not sure how.

multiplyThread中的第49行是“notify()”。我想我需要以不同的方式使用synchronized,但是我不知道如何使用synchronized。

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

如果有人能帮助这个代码工作,我会非常感激。

12 个解决方案

#1


203  

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

#2


63  

While using the wait and notify or notifyAll methods in Java the following things must be remembered:

在使用Java中的wait和notify或notifyAll方法时,必须记住以下事项:

  1. Use notifyAll instead of notify if you expect that more than one thread will be waiting for a lock.
  2. 如果您希望有多个线程等待锁,那么使用notifyAll而不是notify。
  3. The wait and notify methods must be called in a synchronized context. See the link for a more detailed explanation.
  4. 等待和通知方法必须在同步上下文中调用。有关更详细的解释,请参见链接。
  5. 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.
  6. 总是在一个循环中调用wait()方法,因为如果多个线程在等待一个锁,其中一个有锁和重置状态,那么其他线程需要检查条件醒来后再次见到他们是否需要等待或可以开始处理。
  7. 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.
  8. 使用相同的对象调用wait()和notify()方法;每个对象都有它自己的锁,所以在对象A上调用wait()并在对象B上通知()将毫无意义。

#3


20  

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 ExecutorService and Future mechanism to dispatch multiple multiplications simultaneously.

如果您确实需要线程,我将创建'n'线程来执行单元格的乘法(可能'n'是您可用的核心数量),然后使用ExecutorService和Future机制同时执行多个乘法。

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线程工具(这将使工作更容易)。将结果写回接收矩阵中,然后在完成所有未来的任务后打印出来。

#4


13  

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

假设有一个名为BlackBoxClass的类的“黑盒”应用程序,该类具有doSomething()方法。

Further, you have observer or listener named onResponse(String resp) that will be called by BlackBoxClass after 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 BlackBoxClass and when we should get answer but you don't want to continue your code till you get answer or in other word get onResponse call. Here enters 'Synchronize helper':

假设我们不知道BlackBoxClass发生了什么,什么时候我们应该得到答案但是你不想继续你的代码直到你得到答案或者换句话说,get onResponse call。在这里输入“同步助手”:

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

}

#5


7  

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

您只能在拥有它们的监视器的对象上调用notify。所以你需要一些类似的东西

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

#6


6  

notify() needs to be synchronized as well

notify()也需要同步。

#7


3  

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.

我将右击简单的示例,向您展示在Java中使用wait和notify的正确方式。我将创建两个类,名为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);
        }
    }
} 

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

#8


2  

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

通过在同一类的另一个对象上调用notify来恢复这一点

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

#9


1  

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

responce :-

反应:

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

#10


0  

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.

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

#11


0  

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

这看起来是生产者-消费者模式的情况。如果您正在使用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/java/util/concurrent/concurrent/concurrent/blockingqueue.html

#12


0  

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

通过使用synchronized(this)调用wait()方法,您已经正确地保护了代码块。

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

但是,当您调用notify()方法时,没有使用保护块:synchronized(this)或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

如果您参考Object类的oracle文档页面,其中包含wait()、notify()、notifyAll()方法,那么您可以在这三个方法中看到下面的预防措施

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:

在过去的7年里,很多事情都发生了变化,让我们来看看其他替代同步的问题:

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

如果可以使用synchronized(this),为什么要使用ReentrantLock ?

Synchronization vs Lock

同步和锁

Avoid synchronized(this) in Java?

在Java中避免同步(这)?

#1


203  

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

#2


63  

While using the wait and notify or notifyAll methods in Java the following things must be remembered:

在使用Java中的wait和notify或notifyAll方法时,必须记住以下事项:

  1. Use notifyAll instead of notify if you expect that more than one thread will be waiting for a lock.
  2. 如果您希望有多个线程等待锁,那么使用notifyAll而不是notify。
  3. The wait and notify methods must be called in a synchronized context. See the link for a more detailed explanation.
  4. 等待和通知方法必须在同步上下文中调用。有关更详细的解释,请参见链接。
  5. 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.
  6. 总是在一个循环中调用wait()方法,因为如果多个线程在等待一个锁,其中一个有锁和重置状态,那么其他线程需要检查条件醒来后再次见到他们是否需要等待或可以开始处理。
  7. 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.
  8. 使用相同的对象调用wait()和notify()方法;每个对象都有它自己的锁,所以在对象A上调用wait()并在对象B上通知()将毫无意义。

#3


20  

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 ExecutorService and Future mechanism to dispatch multiple multiplications simultaneously.

如果您确实需要线程,我将创建'n'线程来执行单元格的乘法(可能'n'是您可用的核心数量),然后使用ExecutorService和Future机制同时执行多个乘法。

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线程工具(这将使工作更容易)。将结果写回接收矩阵中,然后在完成所有未来的任务后打印出来。

#4


13  

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

假设有一个名为BlackBoxClass的类的“黑盒”应用程序,该类具有doSomething()方法。

Further, you have observer or listener named onResponse(String resp) that will be called by BlackBoxClass after 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 BlackBoxClass and when we should get answer but you don't want to continue your code till you get answer or in other word get onResponse call. Here enters 'Synchronize helper':

假设我们不知道BlackBoxClass发生了什么,什么时候我们应该得到答案但是你不想继续你的代码直到你得到答案或者换句话说,get onResponse call。在这里输入“同步助手”:

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

}

#5


7  

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

您只能在拥有它们的监视器的对象上调用notify。所以你需要一些类似的东西

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

#6


6  

notify() needs to be synchronized as well

notify()也需要同步。

#7


3  

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.

我将右击简单的示例,向您展示在Java中使用wait和notify的正确方式。我将创建两个类,名为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);
        }
    }
} 

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

#8


2  

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

通过在同一类的另一个对象上调用notify来恢复这一点

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

#9


1  

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

responce :-

反应:

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

#10


0  

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.

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

#11


0  

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

这看起来是生产者-消费者模式的情况。如果您正在使用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/java/util/concurrent/concurrent/concurrent/blockingqueue.html

#12


0  

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

通过使用synchronized(this)调用wait()方法,您已经正确地保护了代码块。

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

但是,当您调用notify()方法时,没有使用保护块:synchronized(this)或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

如果您参考Object类的oracle文档页面,其中包含wait()、notify()、notifyAll()方法,那么您可以在这三个方法中看到下面的预防措施

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:

在过去的7年里,很多事情都发生了变化,让我们来看看其他替代同步的问题:

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

如果可以使用synchronized(this),为什么要使用ReentrantLock ?

Synchronization vs Lock

同步和锁

Avoid synchronized(this) in Java?

在Java中避免同步(这)?