一、park & unpack demo
main-start 时间Thu May 13 16:17:32 CST 2021 Thread-0 main-end 时间Thu May 13 16:17:33 CST 2021
特点:该方式实现线程的通信不需要锁,并且可以唤醒指定的线程
Object.wait()、Object.notify() :
- wait和notify都是Object中的方法,在调用这两个方法前必须先获得锁对象,这限制了其使用场合:只能在同步代码块中。
- 当对象的等待队列中有多个线程时,notify只能随机选择一个线程唤醒,无法唤醒指定的线程。
二、LockSupport阻塞和唤醒线程原理
LockSupport是通过控制变量_counter来对线程阻塞唤醒进行控制的。原理有点类似于信号量机制。但是_counter的值只有0或者1
当调用park()方法时,会将_counter置为0,同时判断前值,等于0说明前面被park过,则直接进入排队,否则将使该线程阻塞。
当调用unpark()方法时,会将_counter置为1,同时判断前值,小于1会进行线程唤醒,否则直接退出。
形象的理解,线程阻塞需要消耗凭证(permit),这个凭证最多只有1个。当调用park方法时,如果有凭证,则会直接消耗掉这个凭证然后正常退出;但是如果没有凭证,就必须阻塞等待凭证可用;而unpark则相反,它会增加一个凭证,但凭证最多只能有1个。
为什么可以先唤醒线程后阻塞线程?
因为unpark获得了一个凭证,之后调用park因为有凭证消费,故不会阻塞。
为什么唤醒两次后阻塞两次会阻塞线程。
因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证;而调用两次park却需要消费两个凭证,但我们有且只有一个凭证。