一.LockSupport是什么?
首先看一下官方文档:https://www.apiref.com/java11-zh
乍一看可能还是有些蒙蔽,这里简单的概括一下:
就是一个线程阻塞工具类,所有的方法都是静态的.
二.能干什么
LockSupport类中最常用的方法就是park()和unpark()方法,分别可以阻塞和唤醒线程(作用类似于wait/notify方法)
三.为什么要用这个?和(wait/notify,await/signal)有什么区别?
1.知识点回顾
在之前我们有两种方法可以让一个线程进行阻塞,唤醒,如下所示
2.使用wait/notify存在什么问题?
(1)必须配合Synchronized关键字进行使用,否则会报异常
如上代码,会报非法监视状态异常,那为什么会报这个异常呢?
这个和Synchronized的底层原理有关,详情请看下面的原理图,在执行wait和notify方法时,需要锁定一个对象监视器,这个对象监视器有自己的owner(指向锁的持有者),WaitSet(等待队列,被阻塞的线程就放到这个容器中)等等属性,如果不锁定这个对象,就不能确定在阻塞时所需要的容器等属性,所以在调用wait/notify方法时会先进行判断,没有的话直接抛出异常.
(2)必须先执行wait,notify才能生效,否则就会一致被阻塞.
如上代码,先执行notify方法,再执行wait(),则线程始终会处于阻塞状态.程序无法结束.
其原理是因为会把阻塞的线程放到一个容器中,notify的时候去容器中取,那么直接notify的时候容器中肯定是没有对象的,也就无法生效.
3.使用ReentrantLock的await()和signal()方法也是一样,必须配置lock()方法进行使用,否则会报监视器异常,同时必须先阻塞才能被唤醒
4.使用LockSupport有什么效果呢?
(1)可以直接进行使用,不需要配合其他关键词或方法
(2)即使先执行"唤醒"方法,再执行阻塞方法,线程依旧可以顺利执行
如上,上述代码依旧可以正常执行
四.原理是什么?
为什么LockSupport可以不管顺序却仍能执行成功?原因就在于原理不同
LockSupport引入了许可证的思想,当执行unpark()方法的时候会赋给指定对象一个许可证,执行park()方法的时候判断当前对象是否拥有许可证,没有则进行阻塞,直到其拥有一个许可证才放行,如果拥有则直接放行.放行后将该对象拥有的许可证置空.
LockSupport调用的是Unsafe的native方法
需要注意的是某个对象最多只能拥有1个许可证,这意味着即使我们多次执行unpark方法,在执行一次park方法后,该对象拥有的许可证即为0.
如上代码所示,程序并不会正常结束,而是会一直阻塞.
注意:
在使用LockSupport进行多线程操作时,通常需要配合阻塞队列同步使用,以便存储我们需要唤醒的对象.