JDK1.8 Unsafe类中的park和unpark方法解析
park是Unsafe类中的native方法,LockSupport类通过调用Unsafe类的park和unpark提供了几个操作。Unsafe的park方法如下
public native void park(boolean isAbsolute, long time);
第一个参数判断是否是绝对时间,第二个参数是等待时间值。如果isAbsolute为true则会实现ms定时,如果isAbsolute为false则会实现ns定时。
locksupport类常用的park方法如下,无参方法
public static void park() {UNSAFE.park(false, 0L);
}
执行普通的挂起,isAbsolute是false,time是0.三种情况:1.在调用park()之前调用了unpark或者interrupt则park直接返回,不会挂起。2.如果未调用,则park会挂起当前先线程。3.park未知原因调用出错则直接返回(一般不会出现)。
实现ns计时的方法
public static void parkNanos(long nanos) {if (nanos > 0)UNSAFE.park(false, nanos);}
isAbaolute是false,time大于0,则会实现高精度计时。三种情况:1.在调用park()之前调用了unpark或者interrupt则park直接返回,不会挂起。2.如果未调用则会挂起当前线程,但是在挂起time ns时如果未收到唤醒信号也会返回继续执行。3.park未知原因调用出错则直接返回(一般不会出现)。
实现低精度的ms定时方法
public static void parkUntil(long deadline) {UNSAFE.park(true, deadline);}
此时isAbsolute是true,time可以为任意值。四种情况:1.在调用park()之前调用了unpark或者interrupt则park直接返回,不会挂起。2.如果time<=0,则会挂起当前线程,但是在挂起time ms时如果未收到唤醒信号也会返回继续执行。4.park未知原因调用出错则直接返回(一般不会出现)。
Unsafe调用的park最终会调用Parker类的park函数,Parker继承了PlatformParker。
class PlatformParker : public CHeapObj<mtInternal> {protected:enum {REL_INDEX = 0,ABS_INDEX = 1};int _cur_index; // 条件变量数组下标,which cond is in use: -1, 0, 1pthread_mutex_t _mutex [1] ; //pthread互斥锁pthread_cond_t _cond [2] ; // pthread条件变量数组,一个用于相对时间,一个用于绝对时间。public: // TODO-FIXME: make dtor private~PlatformParker() { guarantee (0, "invariant") ; }public:PlatformParker() {int status;status = pthread_cond_init (&_cond[REL_INDEX], os::Linux::condAttr());assert_status(status == 0, status, "cond_init rel");status = pthread_cond_init (&_cond[ABS_INDEX], NULL);assert_status(status == 0, status, "cond_init abs");status = pthread_mutex_init (_mutex, NULL);assert_status(status == 0, status, "mutex_init");_cur_index = -1; // mark as unused}
};
再看park的实现
void Parker::park(bool isAbsolute, jlong time) {//原子交换,如果_counter > 0,则将_counter置为0,直接返回,否则_counter为0if (Atomic::xchg(0, &_counter) > 0) return;//获取当前线程Thread* thread = Thread::current();assert(thread->is_Java_thread(), "Must be JavaThread");//下转型为java线程JavaThread *jt = (JavaThread *)thread;//如果当前线程设置了中断标志,调用park则直接返回,所以如果在park之前调用了//interrupt就会直接返回if (Thread::is_interrupted(thread, false)) {return;}// 高精度绝对时间变量timespec absTime;//如果time小于0,或者isAbsolute是true并且time等于0则直接返回if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at allreturn;}//如果time大于0,则根据是否是高精度定时计算定时时间if (time > 0) {unpackTime(&absTime, isAbsolute, time);}//进入安全点避免死锁ThreadBlockInVM tbivm(jt);//如果当前线程设置了中断标志,或者获取mutex互斥锁失败则直接返回//由于Parker是每个线程都有的,所以_counter cond mutex都是每个线程都有的,//不是所有线程共享的所以加锁失败只有两种情况,第一unpark已经加锁这时只需要返回即可,//第二调用调用pthread_mutex_trylock出错。对于第一种情况就类似是unpark先调用的情况,所以//直接返回。if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {return;}int status ;//如果_counter大于0,说明unpark已经调用完成了将_counter置为了1,//现在只需将_counter置0,解锁,返回if (_counter > 0) { // no wait needed_counter = 0;status = pthread_mutex_unlock(_mutex);assert (status == 0, "invariant");OrderAccess::fence();return;}OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);jt->set_suspend_equivalent();// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()assert(_cur_index == -1, "invariant");//如果time等于0,说明是相对时间也就是isAbsolute是fasle(否则前面就直接返回了),则直接挂起if (time == 0) {_cur_index = REL_INDEX; // arbitrary choice when not timedstatus = pthread_cond_wait (&_cond[_cur_index], _mutex) ;} else { //如果time非0//判断isAbsolute是false还是true,false的话使用_cond[0],否则用_cond[1]_cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;//使用条件变量使得当前线程挂起。status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;//如果挂起失败则销毁当前的条件变量重新初始化。if (status != 0 && WorkAroundNPTLTimedWaitHang) {pthread_cond_destroy (&_cond[_cur_index]) ;pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());}}//如果pthread_cond_wait成功则以下代码都是线程被唤醒后执行的。_cur_index = -1;assert_status(status == 0 || status == EINTR ||status == ETIME || status == ETIMEDOUT,status, "cond_timedwait");#ifdef ASSERTpthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
#endif//将_counter变量重新置为1_counter = 0 ;//解锁status = pthread_mutex_unlock(_mutex) ;assert_status(status == 0, status, "invariant") ;// 使用内存屏障使_counter对其它线程可见OrderAccess::fence();// 如果在park线程挂起的时候调用了stop或者suspend则还需要将线程挂起不能返回if (jt->handle_special_suspend_equivalent_condition()) {jt->java_suspend_self();}
}
再看unpark函数
void Parker::unpark() {int s, status ;//加互斥锁status = pthread_mutex_lock(_mutex);assert (status == 0, "invariant") ;s = _counter;_counter = 1; //将_counter置1//如果_counter是0则说明调用了park或者没调用(初始为counter0)//这也说明park和unpark调用没有先后顺序。if (s < 1) {// 说明当前parker对应的线程挂起了,因为_cur_index初始是-1,并且等待条件变量的线程被唤醒//后也会将_cur_index重置-1if (_cur_index != -1) {//如果设置了WorkAroundNPTLTimedWaitHang先调用signal再调用unlock,否则相反//这两个先后顺序都可以,在hotspot在Linux下默认使用这种方式//即先调用signal再调用unlockif (WorkAroundNPTLTimedWaitHang) {status = pthread_cond_signal (&_cond[_cur_index]);assert (status == 0, "invariant");status = pthread_mutex_unlock(_mutex);assert (status == 0, "invariant");} else {status = pthread_mutex_unlock(_mutex);assert (status == 0, "invariant");status = pthread_cond_signal (&_cond[_cur_index]);assert (status == 0, "invariant");}} else { //如果_cur_index == -1说明线程没在等待条件变量,则直接解锁pthread_mutex_unlock(_mutex);assert (status == 0, "invariant") ;}} else {//如果_counter == 1,说明线程调用了一次或多次unpark但是没调用park,则直接解锁pthread_mutex_unlock(_mutex);assert (status == 0, "invariant") ;}
JDK1.8 Unsafe类中的park和unpark方法解析相关推荐
- LockSupport 以及 park、unpark 方法
一.LockSupport 是 jsr 166 中新增的 juc 工具类. LockSupport 类主要用于创建锁和其他同步类来实现线程阻塞. 这个类与他使用的每个线程进行关联, 如果可用就立即 p ...
- C#判断一个类中有无指定名称的方法
C#中可以通过反射分析元数据来解决这个问题,示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 2 ...
- 错误: 在类中找不到 main 方法, 请将 main 方法定义为:public static void main(String[] args)否则 JavaFX 应用程序类必须扩展javafx.ap
最近在使用eclipse编写java程序时遇到这样一个问题: 错误在类中找不到main方法,请将main方法定义为 public static void main(String[] args)否则 J ...
- python类定义中__init__()_转:python学习——类中为什么要定义__init__()方法
学习Python的类,一直不太理解为什么一定要定义init()方法,现在简要谈一下自己的理解吧. 1.不用init()方法定义类 定义一个矩形的类,目的是求周长和面积. 1 classRectangl ...
- java实体类没有映射文件_MyBatis自动生成实体类、DAO和XML映射文件,并去掉实体类中的getter和setter方法...
今天花了3个多小时搞定了这个事情,写个Blog记录一下,先看一下最终生成的实体类吧. packagecom.mybatis.pojo;importlombok.AllArgsConstructor;i ...
- java中的actionlistener_JAVA事件监听器之BUTTON类中的ADDACTIONLISTENER(ACTIONLISTENER L)方法...
JAVA:事件监听器之Button类中的addActionListener(ActionListener l)方法 addActionListener public void addActionLis ...
- File类中的list和listFiles方法
File类中的list和listFiles方法 list()方法是返回某个目录下的所有文件和目录的文件名,返回的是String数组 listFiles()方法是返回某个目录下所有文件和目录的绝对路径, ...
- 类中一定要有主方法吗?
类中一定要有主方法吗? 1:不一定要有main,一个项目中可以有多个main,一个项目可以有好好多个类,每个类里面都可以有1个main方法,web应用中不需要经过这些main方法 2:控制台应用中,必 ...
- Java LockSupport以及park、unpark方法源码深度解析
介绍了JUC中的LockSupport阻塞工具以及park.unpark方法的底层原理,从Java层面深入至JVM层面. 文章目录 1 LockSupport的概述 2 LockSupport的特征和 ...
最新文章
- 全球大国人工智能实力大比拼与技术发展趋势
- C#和Javascript间互转的Xxtea加解密
- centos系统光盘的构成简单介绍
- opencv用java完成的例子_SpringBoot整合OpenCV的实现示例
- py函数两个返回值_Python 函数为什么会默认返回 None?
- Cheat Engine 教程( 1 - 9 通关 )
- c 表达式必须是可修改的左值_C++中的左值,右值,左值引用,右值引用
- python json转dict(dict转json)
- bboss_spring_struts2_myibatis对比分析
- anime.js 图片位移动画_打造高大上的Canvas粒子动画
- Dubbo源码解析之SPI(一):扩展类的加载过程
- LINUX EMOS部署及管理
- Java实现:挖金矿问题
- casquette swagg:泉州故事
- AMD显卡怎么提高帧数?AMD显卡提高fps的方法
- 微信公众号如何设置关键词回复Word/Excel/pdf/ppt等文件?
- Java基础强化训练——开发工具及输出语句训练
- 阿里电话面试之所做所得所感(2015年7月)
- FSCapture注册码
- 基于RGB-D数据的语义建图