Java 线程间通信

Java 线程间通信

1 同步阻塞&异步阻塞

同步和异步是相对于执行结果来说,会不会等待结果返回;
阻塞和非阻塞是相对于线程是否被阻塞;
知乎
博客1
博客2

1.1 同步阻塞

一个业务逻辑需要等待上个线程完整的生命周期;
请求量大,程序同一时间受理的数量有限,也就是系统的整体吞吐量不高;
一个线程处理一个请求的方式,会导致频繁创建和销毁线程,会增加系统的额外开销;
业务达到峰值时,大量的业务处理线程阻塞会导致频繁的CPU上下文切换,从而降低系统性能;

1.2 异步阻塞

一个请求来之后会立刻得到一个结果,而系统有若干个业务处理线程,同时处理这个请求,处理结果可从工单等标记获取;
客户端不需要等到程序执行完毕,从而提高了系统的吞吐量和并发量;
服务端线程控制在一定范围内,并进行重复利用,可减少上线程下文切换造成的开销;

2 单个线程间通信

2.1 wait&notify

它们是Object的方法,wait使线程进入阻塞,会释放锁,notify将线程唤醒,仅仅只是通知,不释放锁;

  • wait方法和notify方法都是Object的方法
  • wait()和wait(long,int)最终掉的都是wait(long)这个本地方法
  • notify()和notifyAll()是本地方法
  • 线程A调线程B的wait方法,线程B进入阻塞状态
  • 线程A调线程B的notify方法,线程B被唤醒

Java 线程间通信
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&notify注意事项

  • 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