线程之间的通信主要由四种形式
文件通信,指的是线程之间通过同一个文件的修改进行互相协作通知
网络通信, 指的是线程之间通过网络传输信息进行协作通信
变量通信,指的是线程之间通过共享内存的同一个变量进行修改达到互相协作通知的目的
java api通信,又主要分为
suspend/resume,不推荐使用,因为有两个缺点,一个是不释放锁,第二个是要严格按照加锁解锁的顺序进行,不然会出现死锁现象
不释放锁,指的是当两个线程都在同个对象锁的同步代码块中分别执行了suspend和resume,那么当suspend挂起时不会释放同步代码块的对象锁,而当第二个线程要进入同个对象锁的同步代码块执行resume时,由于对象锁没有释放,导致无法进入同步代码块唤醒线程,从而两个线程都挂起,造成死锁
顺序问题导致的死锁指的是当resume提前调用,而suspend后面调用的话,会导致suspend线程一直等待而到死锁
wait/notify
解决了不释放锁的问题,因为执行wait的时候会释放锁,所以就不存在上文的同一个对象锁下的代码块无法都执行到。
但是依然存在顺序问题导致的死锁,也是因为notify后执行wait,导致wait线程一直挂起,造成死锁
synchronized(ObjectA){
while(不满足条件){
ObjectA.wait();
}
//执行逻辑todo
}
synchronized(ObjectA){
//执行逻辑 todo
ObjectA.notifyAll();
}
park/unpark
解决了顺序问题,因为park/unpark机制是通过发放令牌的机制,也就是说当执行unpark的时候会发放一块令牌,就算unpark先执行,park后执行,也会因为unpark线程已经发放了令牌,而park的时候拿到unpark先前发放的令牌而直接通过执行
但是因为不会释放锁,所以依然存在不释放锁导致的死锁问题.
顺带说一下伪唤醒的概念,存在一种情况就是,当wait/suspend/park 将线程挂起的时候,会存在没有执行notify/resume/unpark ,但是挂起线程依旧醒来继续执行的情况,为了防止这种情况造成的代码逻辑不合原意的情况,我们在判断是否进入等待状态的代码应该使用循环的方式来判断,这样子就可以在线程醒来的情况下再判断一下是否满足醒来的条件从而避免伪唤醒的情况.