我刚刚编写了一个简单的java示例来熟悉wait和notify方法的概念。
这个想法是,当调用notify()
时,主线程将打印总和。
MyThread类
public class MyThread extends Thread {
public int times = 0;
@Override
public void run() {
synchronized (this) {
try {
for (int i = 0; i < 10; i++) {
times += 1;
Thread.sleep(500);
if (i == 5) {
this.notify();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
主要类
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
synchronized (t) {
t.start();
try {
t.wait();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(t.times);
}
}
}
预期结果
5但我得了10个。
嗯,我认为当调用notify()
时,主线程将被唤醒并执行应该给出的System.out.println(t.times)
5.然后run()
将继续直到它完成for循环,它将把时间值更新为10。
非常感谢任何帮助。
答案 0 :(得分:5)
同步块意味着相互排斥。在任何给定时刻,只允许一个线程持有锁并在同步块内执行代码。此规则分布在由同一个锁保护的所有块上。
在你的情况下,有两个这样的块使用相同的锁,因此它是主线程或允许在这些块中的任何一个块中执行代码的MyThread
,另一个线程必须等待。因此,您有以下方案:
wait()
。此调用释放锁定并将主线程置于WAITING
状态。notify()
。此调用不释放锁定,它只是通知主线程一旦可以重新获取锁定就可以进行。times
设置为10并最终离开同步块,释放锁定。println
。但是到了这个时候,times
已经是10。使用join()
也无济于事,因为结果将是相同的 - 主线程只能在第二个完成后才能取得进展。
如果您希望主线程在第二个线程命中5
后继续执行,则需要获取锁定并在该事件发生后立即释放:
public class MyThread extends Thread {
public volatile int times = 0;
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
times += 1;
Thread.sleep(500);
if (i == 5) {
synchronized(this) {
this.notify();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
不要忘记使times
易变,否则JVM将无法保证您在主线程中看到它的实际值。
你还应该明白,这种方法并不能保证主线程打印5.可能会发生这种情况,当它到达println
调用时,第二个线程会进行一次或两次甚至更多次迭代并且你会看到大于5的东西(尽管由于每次迭代都调用sleep()
而非常不幸)。