我正在使用一个整数变量并与两个线程共享。一个线程应该依次打印偶数,一个线程应该打印奇数。 但notify()抛出IllegalMonitorStateException。
package mywaitnotifytest;
public class App {
public static void main(String[] args) {
Integer i=0;
Even even = new Even(i);
even.setName("EvenThread");
Odd odd = new Odd(i);
odd.setName("OddThread");
even.start();
odd.start();
}
}
class Even extends Thread{
Integer var;
Even(Integer var){
this.var=var;
}
@Override
public void run() {
while(true){
synchronized (var) {
if(var%2==0){
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var++;
System.out.println(Thread.currentThread().getName()+" "+var);
var.notify();
}
}
}
}
class Odd extends Thread{
Integer var;
Odd(Integer var){
this.var=var;
}
@Override
public void run() {
while(true){
synchronized (var) {
if(var%2!=0){
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var++;
System.out.println(Thread.currentThread().getName()+" "+var);
var.notify();
}
}
}
}
输出是:
奇数线程 1
Exception in thread "OddThread" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at mywaitnotifytest.Odd.run(App.java:67)
最佳答案
我认为这与给出另一个答案的通常答案有很大不同。
在本例中,您使用的是同步
。当您应用锁时,它是在对象上而不是引用上。
synchronized (var) {
这会锁定对象 var
引用,而不是将 var
作为字段锁定。
var++;
这会替换 var
指向的对象。与此相同
var = Integer.valueOf(var.intValue() + 1);
注意:Integer
实际上所有原始包装器都是不可变的。当您对它们执行任何操作时,您实际上是在拆箱、使用原始值进行计算并重新装箱对象。如果被池化,则可以取回相同的对象。例如
Integer i = 10;
i += 0; // gives back the same object.
但是,如果对象没有被池化
Double d = 10;
d += 0; // creates a new object.
<小时/>
var.notify();
尝试对新对象(而不是已锁定的对象)调用notify
。
您不应该尝试锁定您变异的字段。它不会做它看起来做的事情。您也不应该锁定池对象。在这种情况下,您可以让另一个线程使用相同的 Integer
来实现不相关的目的,并且 notify()
将唤醒一个不相关的线程。
要正确使用等待/通知,您应该
notify()
或notifyAll()
在另一个共享字段中发生状态更改后。- 您应该使用 while 循环进行
wait()
来检查状态更改。
如果你不这样做
- 如果另一个线程没有等待,notify 可能会丢失。
- 即使没有调用任何通知,wait 也可能会被虚假唤醒。
For the above requirement what is the edit suggested in the code? How do i share the same object for multiple threads?
public class PingPong implements Runnable {
static class Shared { int num; }
private final Shared var;
private final int bit;
public static void main(String[] args) {
Shared var = new Shared();
new Thread(new PingPong(var, 0), "EvenThread").start();
new Thread(new PingPong(var, 1), "OddThread").start();
}
PingPong(Shared var, int bit) {
this.var = var;
this.bit = bit;
}
@Override
public void run() {
try {
String name = Thread.currentThread().getName();
while (true) {
synchronized (var) {
while (var.num % 2 == bit)
var.wait();
var.num++;
System.out.println(name + " " + var.num);
var.notify();
}
}
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
关于java等待并通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36566571/