使用static对象作为synchronized锁,多线程调用同实例方法为何两次打印Before a
核心原因
你观察到的现象是Object.wait()方法的固有机制导致的,和synchronized本身的互斥性没有冲突:线程在同步块内调用锁对象的wait()方法时,会主动释放当前持有的锁,进入该锁对象的等待队列阻塞,这个设计是为了让其他线程可以拿到锁,触发notify/notifyAll操作,否则等待的线程永远没有被唤醒的机会,直接形成死锁。
synchronized的互斥性始终生效,同一时间永远只有一个线程持有锁执行同步块内的代码,两次打印Before a是第一个线程释放锁之后,第二个线程才拿到锁进入同步块执行的,并不是两个线程同时进入同步块。
执行流程完整拆解
你提供的代码执行顺序如下:
package com.data; class TestThread { private final static Object object = new Object(); public void myWaitMethod() { synchronized (object) { System.out.println("Before a " + Thread.currentThread().getId()); try { object.wait(); } catch (Exception ignore) { System.out.println(Thread.currentThread().getId()); } System.out.println("After a " + Thread.currentThread().getId()); } } public void myNotifyMethod() { synchronized (object) { System.out.println("Before Notify"); object.notifyAll(); System.out.println("After b"); } } public static void main(String[] args) throws InterruptedException { TestThread aa1 = new TestThread(); new Thread(() -> aa1.myWaitMethod()).start(); new Thread(() -> aa1.myWaitMethod()).start(); Thread.sleep(1000); System.out.println("sleep"); Thread.sleep(1000); aa1.myNotifyMethod(); } }
- 第一个启动的子线程(ID=12)率先抢到
object锁,进入同步块,打印Before a 12,之后调用object.wait(),主动释放object锁,进入object的等待队列阻塞。 - 第二个子线程(ID=13)此时可以拿到刚被释放的
object锁,进入同步块,打印Before a 13,同样调用object.wait(),释放锁后进入等待队列阻塞。 - main线程休眠2秒后调用
myNotifyMethod(),抢到object锁,打印Before Notify,调用notifyAll()唤醒所有在object等待队列的线程,执行完同步块后释放锁。 - 被唤醒的两个子线程需要重新争抢
object锁,抢到锁的线程继续执行wait()之后的逻辑,打印After a后释放锁,另一个线程抢到锁后再执行剩余逻辑,就得到了你看到的输出结果。
补充注意点
被notify/notifyAll唤醒的线程并不会直接继续执行,必须重新抢到对应的锁之后,才会从wait()调用的位置继续往下执行。
内容的提问来源于stack exchange,提问作者azzu112
相关产品推荐
相关产品推荐

