从JDK源码角度看线程的阻塞和唤醒
2016-05-21 08:39
495 查看
目前在Java语言层面能实现阻塞唤醒的方式一共有三种:suspend与resume组合、wait与notify组合、park与unpark组合。其中suspend与resume因为存在无法解决的竟态问题而被Java废弃,同样,wait与notify也存在竟态条件,wait必须在notify之前执行,假如一个线程先执行notify再执行wait将可能导致一个线程永远阻塞,如此一来,必须要提出另外一种解决方案,就是park与unpark组合,它位于JDK的juc包下,应该也是因为当时编写juc时发现java现有方式无法解决问题而引入的新阻塞唤醒方式,由于park与unpark使用的是许可机制,许可最大为1,所以unpark与park操作不会累加,而且unpark可以在park之前执行,如unpark先执行,后面park将不阻塞。 Java真正意义上的语言层面上的并发编程应该从并发专家Doug Lea领导的JSR-166开始,此规范请求向JCP提交了向Java语言中添加并发编程工具,即在jdk中添加java.util.concurrent工具包供开发者使用,开发者可以轻松构建自己的同步器,而在此之前并发过程中同步都只能依靠JVM内置的管程。 JDK的并发包中最重要的一个框架就是ASQ框架,它的阻塞和唤醒使用的是LockSupport类的park与unpark方法,分别调用的是Unsafe类的park与unpark本地方法。逻辑如下:阻塞
唤醒
假如一条线程参与锁竞争,首先先尝试获取锁,失败的话创建节点并插入队列尾部,然后再次尝试获取锁,如若成功则不做其他任务处理直接返回,否则设置节点状态为待运行状态,最后使用LockSupport的park阻塞当前线程。前驱节点运行完后将尝试唤醒后继节点,使用的即是LockSupport的unpark唤醒。 总的来说,JDK提供的并发工具,在阻塞与唤醒操作方面由于suspend与resume存在各种各样问题,必须使用LockSupport中提供的方法操作。
喜欢研究java的同学可以交个朋友:
if(尝试获取锁失败) { 创建node 使用CAS方式把node插入到队列尾部 while(true){ if(尝试获取锁成功 并且 node的前驱节点为头节点){ 把当前节点设置为头节点 跳出循环 }else{ 使用CAS方式修改node前驱节点的waitStatus标识为signal if(修改成功){ LockSupport.park(); } } }
唤醒
if(尝试释放锁成功){ LockSupport.unpark(下一节点包含的线程); }
假如一条线程参与锁竞争,首先先尝试获取锁,失败的话创建节点并插入队列尾部,然后再次尝试获取锁,如若成功则不做其他任务处理直接返回,否则设置节点状态为待运行状态,最后使用LockSupport的park阻塞当前线程。前驱节点运行完后将尝试唤醒后继节点,使用的即是LockSupport的unpark唤醒。 总的来说,JDK提供的并发工具,在阻塞与唤醒操作方面由于suspend与resume存在各种各样问题,必须使用LockSupport中提供的方法操作。
喜欢研究java的同学可以交个朋友:
相关文章推荐
- 从JDK源码角度看线程的阻塞和唤醒
- Java NIO:NIO概述
- 常用的函数接口
- 函数接口
- [Java]阶段性知识点、技术总结
- Lambda表达式操作引用值,而非对象
- Lambda表达式类型推断
- java环境配置为1.7jdk为什么cmd java -version查看版本是1.8
- java设计模式之模板方法模式
- 理解Java最重要的8张图
- Java的反射机制
- IntelliJ使用指南—— 导入Eclipse的Web项目
- spring源码剖析(八)spring整合mybatis原理
- java学习、java教程、java编程:怎样才算是编程高手?
- java中HashMap详解
- Spring+Hibernate多数据源配置
- spring mvc 中通过controller 传递对象给jsp,并且数据绑定,在修改值后回传对象给controller
- MyEclipse 2014 破解图文详细教程
- MyEclipse 2014 破解图文详细教程
- 关于Struts2 <s:iterator><s:if><s:elseif><s:else>标签备忘录