[关闭]
@boothsun 2017-09-03T12:29:10.000000Z 字数 2239 阅读 1192

LockSupport学习

Java多线程


LockSupport工具类定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能。Java锁和同步器框架的核心工具类AQS:AbstractQueueSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒。

LockSupport很类似于二元信号量(只有1个许可证可供使用),如果这个许可证还没有被占用,当前线程获取许可并继续执行。如果许可已经被占用,当前线程阻塞,等待获取许可。但是这个许可是不能叠加的,“许可”是一次性的。

比如线程B连续调用了三次unpark函数,当前线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态。

注意:unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个“许可”,那么当线程A调用park时,它发现已经有“许可”了,那么它会马上再继续运行。

park和unpark的灵活之处

上面已经提到了,unpark函数可以先于park调用,这个正是它们的灵活之处。

一个线程它有可能在别的线程unpark之前,或者之后,或者同时调用park,那么因为park的特性,它可以不用担心自己的park的时序问题,否则,如果park必须要在unpark之前,那么给编程带来很大的麻烦!!

考虑一下,两个线程同步,要如何处理?

在Java5里是用wait/notify/notifyAll来同步的。wait和notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。编程的时候就会很蛋疼。

另外,是调用notify,还是notifyALL?

notify只会唤醒一个线程,如果错误地有两个线程在同一个对象上wait等待,那么又悲剧了。为了安全起见,貌似只能调用nofityAll了。

park和unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Objec或者其他变量来存储状态,不再需要关心对方的状态。

LockSupport API的使用

LockSupport提供的阻塞和唤醒方法

方法名 方法摘要
static void park() 阻塞当前线程,如果调用了unpark(Thread thread)方法或者当前线程被中断,才能park()方法返回
static void unpark() 唤醒处于阻塞状态的线程thread
static void parkNanos(long nanos) 阻塞当前线程,最长不超过nanos纳米,返回条件在park()的基础上增加了超时返回
static void parkUntil(long dealine) 在指定的时限前阻塞当前线程

LockSupport 简单使用

  1. public static void main(String[] args) {
  2. Executor executor = Executors.newFixedThreadPool(2);
  3. Thread mainThread = Thread.currentThread() ;
  4. executor.execute(()->{
  5. try {
  6. Thread.sleep(3000L);
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. System.out.println("start unpark main thread");
  11. LockSupport.unpark(mainThread);
  12. System.out.println("unpark main thread over");
  13. });
  14. System.out.println("before park");
  15. LockSupport.park();
  16. System.out.println("after park ");
  17. }

运行结果:

先释放许可,再获取许可

  1. @Test
  2. public void test1() {
  3. Thread thread = Thread.currentThread();
  4. LockSupport.unpark(thread);//释放许可
  5. LockSupport.park();// 获取许可
  6. System.out.println("b");
  7. }

中断响应

  1. public static void main(String[] args) {
  2. Executor executor = Executors.newFixedThreadPool(2);
  3. Thread mainThread = Thread.currentThread() ;
  4. executor.execute(()->{
  5. try {
  6. Thread.sleep(3000L);
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. System.out.println("start interrupt main thread");
  11. mainThread.interrupt();
  12. System.out.println("interrupt main thread over");
  13. });
  14. System.out.println("before park");
  15. LockSupport.park();
  16. LockSupport.park();
  17. System.out.println("after park ");
  18. }

运行截图:

原理和本文参考

详见:Java的LockSupport.park()实现分析

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注