线程通信学习小结

线程通信浅析

java支持多线程执行,线程之间需要进行数据交互,消息传输,必然会存在线程间的通信。例如:线程自旋,线程等待,锁,线程唤醒等。下面介绍几种线程通信api说明

1、suspend/resume组合

此组合以及被jdk废弃掉。
原因:此通信api很容易导致线程通信的死锁。
死锁示例共两个代表示例:

a) 两个线程同时使用同一个对象锁,相互持有锁时,就会出现死锁情况。

线程通信学习小结
b) 执行resume方法的线程早于执行suspend的方法线程执行,会导致死锁

线程通信学习小结

2、wait/notify(notifyAll)组合

此组合成功替代上面suspend组合
优点:线程间抢锁过程中,wait方法执行线程会释放锁对象,进行waiting队列中,等待被notify唤醒。
缺点:
a) 会出现死锁场景。比如:notify() 方法线程早于wait()方法线程执行。
b)是基于对象监视器使用,故必须与Synchronized代码块一起使用

正常使用code:
线程通信学习小结
死锁(唤醒早于等待执行)
线程通信学习小结

3、park/unpark()

优点:不会因为执行顺序发生死锁的问题。

缺点:park方法不会释放锁对象,同样可能产生死锁。

park:可以理解为等待线程"颁发"的"许可"

unpark:可以理解为为某线程"颁发许可证"

许可证是可以提前颁发的,但是许可证只允许拿一次,即使是同一个线程等待许可证

见code:
线程通信学习小结
产生死锁场景:
线程通信学习小结

注意线程等待的伪唤醒解决

上面示例截图代码中,其实是有问题的。

线程通信学习小结
if 条件判断使用可能会出现问题,当判断条件不是由notify或者notifyAll()方法唤醒时,而是由于其他原因唤醒的(伪唤醒),就会出现问题。

所以JDK官方建议开发者在此类场景下使用while(true)来解决,将if判断条件换为循环判断。