1. LockSupport原理
LockSupport是一个编程工具类,主要是为了阻塞和唤醒线程用的。
LockSiupport的核心方法有两个,park和unpark,park用来阻塞当前调用线程,unpark用来唤醒指定线程。
LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,可以把许可看成是一种(0,1)信号量(Semaphore),但与 Semaphore 不同的是,许可的累加上限是1。
初始时,permit为0,当调用unpark()方法时,线程的permit加1,当调用park()方法时,如果permit为0,则调用线程进入阻塞状态。
2. 和Object类中的wait,notify区别
(1)wait、notify都是Object中的方法,在调用这两个方法前必须先获得锁对象,但是park不需要获得某个对象的锁就可以锁住线程。
(2)notify只能随机选择一个线程唤醒,无法对指定线程进行操作,unpark可以对指定线程唤醒。
3. LockSupport阻塞和唤醒线程原理
LockSupport就是通过控制变量_counter来对线程阻塞唤醒进行控制的。原理有点类似于semaphore信号量机制。
形象的理解,线程阻塞需要消耗凭证(permit),这个凭证最多只有1个。当调用park方法时,如果有凭证,则会直接消耗掉这个凭证然后正常退出;但是如果没有凭证,就必须阻塞等待凭证可用;而unpark则相反,它会增加一个凭证,但凭证最多只能有1个。
为什么可以先唤醒线程后阻塞线程?
因为unpark获得了一个凭证,之后再调用park因为有凭证消费,故不会阻塞。
为什么唤醒两次后阻塞两次会阻塞线程?
因为凭证的数量最多为1,连续调用2次unpark和1次unpark效果一样,只会增加一个凭证;但调用2次park则需要消耗2次凭证。
4. 总结
LockSupport是JDK用来实现线程阻塞和唤醒的工具,使用它可以在任何场合使线程阻塞,可以指定任何线程进行唤醒,不用担心阻塞和唤醒操作的顺序,不过要注意连续多次唤醒和一次唤醒的效果是一样的。
JDK并发包下的锁和其他同步工具的底层实现中大量使用了LockSupport进行线程的阻塞和唤醒。