如何在Java中使用wait和notify?
我有2个matrix,我需要将它们相乘,然后打印每个单元格的结果。 只要一个单元准备就绪,我需要打印它,但是例如,即使[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)
multiplyThread
中的第49行是“notify()”..我想我需要使用不同的同步,但我不知道如何。
如果任何人都可以帮助这个代码工作,我将非常感激。
为了能够调用notify(),你需要在同一个对象上进行同步。
synchronized (someObject) { someObject.wait(); } /* different thread / object */ synchronized (someObject) { someObject.notify(); }
在Java中使用wait
和notify
或notifyAll
方法时,必须记住以下事项:
- 如果您期望多个线程将等待locking,请使用
notifyAll
而不是notify
。 -
wait
和notify
方法必须在同步的上下文中调用 。 请参阅链接以获取更详细的解释。 - 总是在一个循环中调用
wait()
方法,因为如果多个线程正在等待一个锁,并且其中一个线程获得了锁并重置了条件,那么其他线程在唤醒之后需要检查它们是否需要再等一等,或者可以开始处理。 - 使用相同的对象来调用
wait()
和notify()
方法; 每个对象都有自己的锁,所以在对象A上调用wait()
,在对象B上调用notify()
将没有任何意义。
你需要线程吗? 我想知道你的matrix有多大,是否有一个线程打印,而另一个线程乘法有什么好处。
在做相对复杂的线程工作之前,也许这个时间值得去衡量一下。
如果你确实需要线程的话,我会创build'n'个线程来执行单元的乘法(也许'n'是你可用的内核的数量),然后使用ExecutorService和Future机制同时分派多个乘法。
这样你就可以根据内核的数量来优化工作,而且你正在使用更高级别的Java线程工具(这会让生活变得更容易)。 将结果写回到接收matrix中,然后只要所有未来任务完成,就简单地打印出来。
比方说,你有一个名为BlackBoxClass
类的黑盒子应用程序,它有方法doSomething();
。
此外,你有名为onResponse(String resp)
观察者或监听者,在未知的时间之后将被BlackBoxClass
调用。
stream程很简单:
private String mResponse = null; ... BlackBoxClass bbc = new BlackBoxClass(); bbc.doSomething(); ... @override public void onResponse(String resp){ mResponse = resp; }
假设我们不知道BlackBoxClass
发生了什么事情,当我们应该得到答案,但是你不想继续你的代码,直到你得到答案或换句话说得到onResponse
调用。 这里input“同步助手”:
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()
需要同步
我会正确的简单的例子显示你正确的方式来使用wait
并在Java notify
。 所以我将创build两个名为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 } } }
我们可以调用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!"); }
通过在同一个类的另一个对象上调用notify来恢复它
public synchronized notifyJoy() { joy = true; notifyAll(); }
简单的使用,如果你想如何执行线程交替: –
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(); } }
回应: –
T1:A T2:B T1:A T2:B T1:A T2:B T1:A T2:B T1:A T2:B T1:A T2:B
对于这个特定的问题,为什么不把你的各种结果存储在variables中,然后当你的线程的最后一个被处理时,你可以打印任何你想要的格式。 如果您要在其他项目中使用您的工作历史,这一点尤其有用。
这看起来像生产者 – 消费者模式的情况。 如果您使用的是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
当您使用synchronized(this)
调用wait()
方法时,您已妥善保护您的代码块。
但是,如果调用notify()
方法而不使用保护块,则没有采取相同的措施: synchronized(this)
或synchronized(someObject)
如果你参考Object类的oracle文档页面,其中包含wait()
, notify()
, notifyAll()
方法,你可以在下面的三个方法中看到预防措施
这个方法只能由这个对象监视器的所有者的线程调用
在过去的7年里,许多事情已经发生了变化,让我们看看其他的select,以便在SE问题下synchronized
:
为什么使用ReentrantLock如果可以使用synchronized(this)?
同步与locking
避免在Java中同步(this)?