notify方法放置位置异常:run方法调用失效,deposit方法调用正常
问题:wait()无法被run方法中notify()唤醒的原因及解决办法
我在测试Java的wait()和notify()方法时发现,将notify()放在deposit方法中时可以正常唤醒等待的线程,但把notify()放到Thread 2的run方法里(无论调用deposit方法前后)都无法生效,程序会进入无限等待状态。
原代码:
public class NewProgram { static int balance = 0; public void withdraw(int amount) { synchronized(this) { if(balance== 0) { try{ System.out.println("Waiting for deposit"); wait(); } catch(InterruptedException e) { e.printStackTrace(); } } } balance = balance - amount; System.out.println("Amount Withdrawn Successfully"); } public void deposit(int amount) { balance = balance + amount; System.out.println("Money Deposited Successfully"); // The Notify method here works // synchronized(this) // { // notify(); // }} public static void main(String[] args) { NewProgram app = new NewProgram(); Thread thread1 = new Thread (new Runnable(){ @Override public void run(){ app.withdraw(2000); } }); thread1.start(); Thread thread2 = new Thread(new Runnable(){ @Override public void run() { try { Thread.sleep(5000); // The Notify method here doesn't work // synchronized(this) { // notify(); // } } catch (InterruptedException e) { e.printStackTrace(); } app.deposit(3000); // The notify method from here doesn't work //synchronized(this) { // notify(); //} System.out.println("Thread 2 ends"); } }); thread2.start(); }}
问题根源
核心问题是锁对象不匹配:
- withdraw方法中的wait()是在
app(NewProgram类的实例)对象的同步块中调用的,线程1持有app对象的锁,并在该对象上进入等待状态。 - 而run方法里
synchronized(this)中的this,指向的是当前Runnable匿名内部类的实例,并非app对象。在这个无关的Runnable实例上调用notify(),根本无法唤醒在app对象上等待的线程。
解决办法
要唤醒在app对象上等待的线程,必须在app对象的同步块中调用notify()。修改Thread 2的run方法如下:
Thread thread2 = new Thread(new Runnable(){ @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } app.deposit(3000); // 锁定app对象,在该对象上调用notify() synchronized(app) { app.notify(); } System.out.println("Thread 2 ends"); } });
额外注意事项
- 防止虚假唤醒:建议用
while循环替代if判断等待条件,因为线程可能被虚假唤醒,需要重新检查条件是否满足:
public void withdraw(int amount) { synchronized(this) { // 用while循环重复检查余额 while(balance == 0) { try{ System.out.println("Waiting for deposit"); wait(); } catch(InterruptedException e) { e.printStackTrace(); } } } balance = balance - amount; System.out.println("Amount Withdrawn Successfully"); }
- wait()、notify()/notifyAll()必须在持有对应对象锁的同步块/方法中调用,且操作的必须是同一个对象,否则无法正常实现线程间通信。
内容的提问来源于stack exchange,提问作者Anonymous_1354
相关产品推荐
相关产品推荐

