如何在没有 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
How to use wait and notify in Java without IllegalMonitorStateException?
提问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 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 个矩阵,我需要将它们相乘,然后打印每个单元格的结果。一个单元格准备好后,我需要打印它,但例如,即使 [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 multiplyThread
is 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
回答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”是您可用的内核数),然后使用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 线程工具(这应该会让生活更轻松)。将结果写回接收矩阵,然后在所有未来任务完成后简单地打印出来。
回答by Hymanob
While using the wait
and notify
or notifyAll
methods in Java the following things must be remembered:
在 Java 中使用wait
andnotify
或notifyAll
方法时,必须记住以下几点:
- Use
notifyAll
instead ofnotify
if you expect that more than one thread will be waiting for a lock. - The
wait
andnotify
methods must be called in a synchronized context. See the link for a more detailed explanation. - 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. - Use the same object for calling
wait()
andnotify()
method; every object has its own lock so callingwait()
on object A andnotify()
on object B will not make any sense.
- 如果您期望多个线程等待锁定,请使用
notifyAll
代替notify
。 - 该
wait
和notify
方法必须在同步上下文中调用。有关更详细的解释,请参阅链接。 - 总是
wait()
在循环中调用该方法,因为如果多个线程正在等待一个锁并且其中一个线程获得了锁并重置了条件,那么其他线程需要在它们醒来后检查条件以查看是否需要再次等待或可以开始处理了。 - 调用
wait()
和notify()
方法使用同一个对象;每个对象都有自己的锁,因此调用wait()
对象 A 和notify()
对象 B 没有任何意义。
回答by Maxim Shoustin
Let's say you have 'black box' application with some class named BlackBoxClass
that has method doSomething();
.
假设您有一个“黑匣子”应用程序,其中包含一些名为BlackBoxClass
method 的类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
以及何时应该得到答案,但您不想继续您的代码,直到您得到答案或换句话说就是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 wait
and notify
in Java.
So I'll create two class named ThreadA& ThreadB. ThreadA will call ThreadB.
我将正确的简单示例向您展示在 Java 中使用wait
和使用的正确方法notify
。所以我将创建两个名为ThreadA和ThreadB 的类。线程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();
}