Java循环内synchronized同步块共享锁的线程执行结果疑问
synchronized锁连续分配给同一持有线程的现象说明
现象原因
你观察到的输出是HotSpot JVM的锁优化逻辑和操作系统线程调度共同作用的正常结果,不属于bug,核心原因如下:
- Java语言规范从未要求
synchronized关键字对应的内部锁必须使用公平调度策略,默认的实现是不公平锁,允许刚释放锁的线程优先再次获得锁,避免线程上下文切换带来的性能损耗。 - 你的测试代码中同步块的执行逻辑极短,仅包含一行打印操作,第一个启动的MorningThread释放锁之后,EveningThread还没完成从阻塞状态被唤醒的上下文切换,MorningThread已经进入下一轮循环再次申请同一把锁,此时JVM会直接把锁再分配给MorningThread。
- Windows操作系统本身的线程调度策略会给正在运行的线程分配更长的时间片,进一步放大了这个效应,所以你会稳定看到连续两次Good Morning输出后才会输出Evening的内容。
对应官方说明
《Java语言规范》(Java Language Specification)第17章并发部分明确规定:JVM实现可以自由选择
synchronized内部锁的调度算法,不保证锁分配的公平性,也不保证等待队列中的线程按顺序获得锁。
如果你想要实现交替输出的效果,可以在每次退出同步块后主动调用Thread.sleep(1)主动让出CPU,给另一个线程足够的时间抢锁,修改后的run方法参考如下:
public void run() { for (int i = 0; i < 2; i++) { synchronized(lock) { System.out.println("Good Morning"); } try { Thread.sleep(1); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
内容的提问来源于stack exchange,提问作者Ravi Krishna P
相关产品推荐
相关产品推荐

