• AQS阻塞唤醒工具LockSupport



    LockSupport在JDK源码中描述为:构建锁和其他同步类的基本线程阻塞原语,构建更高级别的同步工具集。LockSupport提供的park/unpark从线程的粒度上进行阻塞和唤醒,park/unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Object或者其它变量来存储状态。

    本文从阻塞唤醒的语义入手,解释LockSupport的内在机制和注意点,最后与Object的wait和notify做对比,包括以下内容:

    • 阻塞和唤醒的语义
    • 许可机制
    • 底层实现
    • 用法
    • 与Object的wait和notify区别

    阻塞的语义

    阻塞是线程在满足某种条件之前暂时停止运行,而被动释放出CPU资源。进入该状态的线程不会主动进入线程队列等待CPU资源,而需要等待满足条件后被唤醒,才能让该线程重新进入到线程队列中排队等待CPU资源。一般造成线程阻塞的原因有:等待获取一个已经被其他线程持有的排他锁、等待某一操作结束、等待某一个时间段。线程阻塞后会被挂起,此时会处于BLOCKEDWAITINGTIMED_WAITING。线程阻塞后会让出CPU资源,这是为避免在自旋上浪费过多的CPU资源,是忙等待(busy wait)的一种优化。

    许可机制

    LockSupport通过“许可”(permit)机制,使用park/unpark实现线程的阻塞和唤醒。许可是指允许线程继续执行,是线程执行的开关,当开关关闭时,线程会阻塞,当开关打开时,线程会立即执行。

    park意指线程在获取许可之前会暂停执行(阻塞在获取许可)。这里的“许可”与线程相关联,类似二元信号量,不可叠加且一个线程只能有一个。有些文章描述“许可”是一次性的,例如当线程A调用park消耗掉一个“许可”(最多只有一个“许可”),在未调用unpark释放出线程A的该“许可”之前,线程A再次调用park时会阻塞在获取“许可”。下文引自Understanding JVM Thread States

    there can be only one permit per thread, when thread consumes the permit, it disappears.

    出于线程调度的目的,调用park时会阻塞直到许可可用时。如果许可可用,调用park就会立即返回。当前线程就会阻塞,直到调用 unpark 方法,释放出许可。由于许可是默认被占用的,当前线程在启动后调用 park 的话就获取不到许可,因此就进入阻塞状态。

    底层实现

    LockSupport是使用Unsafe的park实现的,HotSpot Parker用condition和mutex维护了一个_counter变量,park时,变量_counter置为0,unpark时,变量_counter置为1。park操作检查该值是否为1,为1直接返回;不为1,则阻塞。

    用法

    看到一个关于park/unpark通俗易懂的的例子,代码如下:

     1 public static void main(String[] args) throws InterruptedException {
     2   Thread threadA = new Thread(new Runnable() {
     3     @Override
     4     public void run() {
     5       System.out.println("周末了我在打游戏");
     6       LockSupport.park();
     7       System.out.println("陪女朋友逛逛街");
     8     }
     9   });
    10   threadA.start();
    11   Thread.sleep(3000);
    12   System.out.println("女朋友准备要喊男朋友逛街");
    13   LockSupport.unpark(threadA);
    14 }

    在第6行park执行操作时,线程尝试获取许可,由于线程threadA在启动后默认已经获取了许可,park必须等待许可释放后才可以执行。当主线程调用unpark方法释放threadA的许可,threadA才可以继续执行第7行。 

    与wait和notify区别

    park/unpark与wati/notify都提供阻塞唤醒的功能,用做线程间同步,不过两者 的粒度不同,park/unpark作用在线程上,而wait/notify作用在对象上,二者没有交集。Object的wait/notify使用前必须获取对象的监视器,而park/unpark不需要。

    写作不易,痛并快乐着;理解可能存在偏差,句句斟酌推敲;抵制抄袭,践行原创技术之路。如果本文能对您有所帮助,实为荣幸,我是葛一凡。

    原文
    微信公众号微信公众号

    参考

      1. Java的LockSupport.park()实现分析
      2. java线程阻塞中断和LockSupport的常见问题
      3. 多线程之Java线程阻塞与唤醒
      4. Understanding JVM Thread States
      5. java并发包系列—LockSupport
      6. Java并发包源码学习之AQS框架(三)LockSupport和interrupt
  • 相关阅读:
    一些端口
    outlook 的微软手册
    目录摘要
    L2TP的包过滤规则
    outlook 的外出时助理程序对外部邮箱不起作用。1个解决办法和另外一个可能性
    用editplus 正则表达式修改联系人表
    Cisco NAT的理解。
    outlook 2003 无法记住密码
    ERD commander 2005的下载地址。
    outlook 2003启用日志记录排除故障。
  • 原文地址:https://www.cnblogs.com/geyifan/p/6599285.html
Copyright © 2020-2023  润新知