调用wait()进入等待的Java线程能否自行调用notify()唤醒自己?
Java自定义线程挂起/等待实现逻辑答疑
示例代码
// Suspending and resuming a thread the modern way. class NewThread implements Runnable { String name; // name of thread Thread t; boolean suspendFlag; NewThread(String threadname) { name = threadname; t = new Thread(this, name); System.out.println("New thread: " + t); suspendFlag = false; t.start(); // Start the thread } // This is the entry point for thread. public void run() { try { for (int i = 15; i > 0; i--) { System.out.println(name + ": " + i); Thread.sleep(200); synchronized(this) { while (suspendFlag) { wait(); } } } } catch (InterruptedException e) { System.out.println(name + " interrupted."); } System.out.println(name + " exiting."); } void mysuspend() { suspendFlag = true; } synchronized void myresume() { suspendFlag = false; notify(); } } class SuspendResume { public static void main(String args[]) { NewThread ob1 = new NewThread("One"); NewThread ob2 = new NewThread("Two"); try { Thread.sleep(1000); ob1.mysuspend(); System.out.println("Suspending thread One"); Thread.sleep(1000); ob1.myresume(); // 后续代码省略
核心理解偏差说明
你产生疑问的根本原因是混淆了执行方法的线程主体:
调用ob1.mysuspend()、ob1.myresume()的是main主线程,而处于等待队列阻塞的是ob1实例关联的子线程ob1.t,二者是完全独立的两个执行流,不存在「阻塞线程自己调用方法唤醒自己」的逻辑。
实际运行机制完整流程
我们以ob1的生命周期为例,完整执行逻辑如下:
- 实例化
ob1时,会自动启动子线程ob1.t,该子线程独立执行run方法中的循环逻辑 - main线程调用
ob1.mysuspend():该方法无同步修饰,直接修改成员变量suspendFlag = true,执行过程不需要拿锁,瞬间完成 ob1.t执行到run方法中的synchronized(this)代码块时,先拿到ob1实例的对象锁,判断suspendFlag为true后调用wait():调用wait方法的瞬间,ob1.t会自动释放持有的ob1对象锁,之后进入ob1实例的等待队列阻塞,此时ob1的对象锁回到空闲状态- main线程调用
ob1.myresume():该方法为同步方法,需要先获取ob1实例的对象锁,由于此时锁是空闲的,main线程可以直接拿到锁,先修改suspendFlag = false,再调用notify()唤醒等待队列中的ob1.t,方法执行完成后main线程自动释放ob1的对象锁 - 被唤醒的
ob1.t会重新竞争ob1的对象锁,拿到锁后会退出while循环,继续执行后续的循环逻辑
补充注意点
该示例为了简化演示省略了安全处理,实际生产中使用需要给mysuspend方法也增加synchronized修饰,或者给suspendFlag变量加volatile修饰,避免多线程环境下的可见性问题。
内容的提问来源于stack exchange,提问作者stkUser
相关产品推荐
相关产品推荐

