Java 线程间通信
Java 线程间通信
1 同步阻塞&异步阻塞
同步和异步是相对于执行结果来说,会不会等待结果返回;
阻塞和非阻塞是相对于线程是否被阻塞;
知乎
博客1
博客2
1.1 同步阻塞
一个业务逻辑需要等待上个线程完整的生命周期;
请求量大,程序同一时间受理的数量有限,也就是系统的整体吞吐量不高;
一个线程处理一个请求的方式,会导致频繁创建和销毁线程,会增加系统的额外开销;
业务达到峰值时,大量的业务处理线程阻塞会导致频繁的CPU上下文切换,从而降低系统性能;
1.2 异步阻塞
一个请求来之后会立刻得到一个结果,而系统有若干个业务处理线程,同时处理这个请求,处理结果可从工单等标记获取;
客户端不需要等到程序执行完毕,从而提高了系统的吞吐量和并发量;
服务端线程控制在一定范围内,并进行重复利用,可减少上线程下文切换造成的开销;
2 单个线程间通信
2.1 wait¬ify
它们是Object的方法,wait使线程进入阻塞,会释放锁,notify将线程唤醒,仅仅只是通知,不释放锁;
- wait方法和notify方法都是Object的方法
- wait()和wait(long,int)最终掉的都是wait(long)这个本地方法
- notify()和notifyAll()是本地方法
- 线程A调线程B的wait方法,线程B进入阻塞状态
- 线程A调线程B的notify方法,线程B被唤醒
wait:
使线程进入到竞争monitor锁的wait Set中,并处于阻塞状态;
wait方法的三个重载方法都调用wait(long timeout)这个方法;
wait方法会导致线程进入阻塞状态,只有其他线程调用Object的notify或notifyAll方法或阻塞时间到达后,才可将其唤醒;
wait方法必须拥有该对象的monitor锁,也就是wait方法必须在同步方法中使用;
当前线程执行了该对象的wait方法后,就失去了该对象的monitor锁,并进入其wait set中;
notify:
唤醒竞争monitor锁而陷入阻塞状态的线程;
唤醒单个正在执行对象wait方法的线程;
如果有某个线程由于执行该对象wait方法而进入阻塞则会被唤醒,如果没有则忽略;
被唤醒的线程需要重新竞争该对象所关联的monitor锁才能继续执行;
2.2 wait¬ify注意事项
- wait是可中断方法,当前线程一旦调用wait方法进入阻塞状态,其他线程调用Intterput方法可将其打断,被打断后会跑出InterruptedException;
- 线程执行了某个对象的wait方法后,会加入与之对应的wait set中,每个对象的Monitor 锁都有一个与之关联的set;
- 当线程进入monitor set后,notify方法可以将其唤醒,也就是冲wait set中将其弹出;
- 必须在同步方法中使用wait和notify方法,因为执行wait和notifu的前提调教是必须持有同步方法的monitor锁;
- 同步代码的monitor必须与执行wait notify方法的对象一致;
2.3 wait&sleep:
- wait和sleep方法都可以使线程进入阻塞状态;
- wait和sleep方法都是可中断方法,中断后收到中断异常;
- wait是Object的方法,sleep是Thread的方法;
- wait方法必须执行在同步方法中,而sleep不需要;
- 同步方法中执行sleep不会释放monitor锁,而wait会;
3 多线程间通信
与单线程间通信的区别是notify和notifyAll的区别;
4 自定义显示锁
BooleanLock