要想实现多个线程之间的协同,如:线程执行先后顺序、获取某个线程执行的结果等。 涉及到线程之间相互通信,分为如下四类:
socket编程
细分为: suspend/resume 、 wait/notify、 park/unpark
JDK中对于需要多线程协作完成某一任务的场景,提供了对应API支持。 多线程协作的典型场景是:生产者-消费者模型。(线程阻塞、 线程唤醒)
但该组合很容易写出
所以用如下机制替代
这些方法只能由同一对象锁的持有者线程调用,即写在同步块里!否则抛IllegalMonitorStateException。
wait 方法导致当前线程等待,加入该对象的等待集合中,并且放弃当前持有的对象锁。
notify/notifyAll 方法唤醒一个/所有正在等待这个对象锁的线程。
虽然wait会自动解锁,但对顺序有要求。若在notify被调用后, 才调用wait,则线程会永远处于WAITING态。
线程先要获得并持有锁,必须在锁块(synchronized或lock)中。必须要先等待后唤醒,线程才能够被唤醒。
LockSupport用来创建锁和其他同步类的基本线程阻塞原语:
LockSupport.park
,则等待“许可”LockSupport.unpark
,必须把等待获得许可的线程作为参数进行传递,好让此线程继续运行,为指定线程提供“许可(permit)”不要求park和unpark方法的调用顺序,无需写在任何同步代码块里。
多次调用unpark之后,再调用park,线程会直接运行,不会叠加,累加上限只有 1,即连续多次调用park,第一次会拿到“许可”直接运行,后续调用还是会进入等待。
之前代码中用if语句来判断,是否进入等待状态,是错误的。
官方推荐应该在循环中检查等待条件
,因为处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就可能在没有满足结束条件的情况下退出。
伪唤醒是指线程并非因为notify、notifyall、 unpark等API调用而唤醒,而是更底层原因导致的。