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方法解析相关推荐

  1. LockSupport 以及 park、unpark 方法

    一.LockSupport 是 jsr 166 中新增的 juc 工具类. LockSupport 类主要用于创建锁和其他同步类来实现线程阻塞. 这个类与他使用的每个线程进行关联, 如果可用就立即 p ...

  2. 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 ...

  3. 错误: 在类中找不到 main 方法, 请将 main 方法定义为:public static void main(String[] args)否则 JavaFX 应用程序类必须扩展javafx.ap

    最近在使用eclipse编写java程序时遇到这样一个问题: 错误在类中找不到main方法,请将main方法定义为 public static void main(String[] args)否则 J ...

  4. python类定义中__init__()_转:python学习——类中为什么要定义__init__()方法

    学习Python的类,一直不太理解为什么一定要定义init()方法,现在简要谈一下自己的理解吧. 1.不用init()方法定义类 定义一个矩形的类,目的是求周长和面积. 1 classRectangl ...

  5. java实体类没有映射文件_MyBatis自动生成实体类、DAO和XML映射文件,并去掉实体类中的getter和setter方法...

    今天花了3个多小时搞定了这个事情,写个Blog记录一下,先看一下最终生成的实体类吧. packagecom.mybatis.pojo;importlombok.AllArgsConstructor;i ...

  6. java中的actionlistener_JAVA事件监听器之BUTTON类中的ADDACTIONLISTENER(ACTIONLISTENER L)方法...

    JAVA:事件监听器之Button类中的addActionListener(ActionListener l)方法 addActionListener public void addActionLis ...

  7. File类中的list和listFiles方法

    File类中的list和listFiles方法 list()方法是返回某个目录下的所有文件和目录的文件名,返回的是String数组 listFiles()方法是返回某个目录下所有文件和目录的绝对路径, ...

  8. 类中一定要有主方法吗?

    类中一定要有主方法吗? 1:不一定要有main,一个项目中可以有多个main,一个项目可以有好好多个类,每个类里面都可以有1个main方法,web应用中不需要经过这些main方法 2:控制台应用中,必 ...

  9. Java LockSupport以及park、unpark方法源码深度解析

    介绍了JUC中的LockSupport阻塞工具以及park.unpark方法的底层原理,从Java层面深入至JVM层面. 文章目录 1 LockSupport的概述 2 LockSupport的特征和 ...

最新文章

  1. 全球大国人工智能实力大比拼与技术发展趋势
  2. C#和Javascript间互转的Xxtea加解密
  3. centos系统光盘的构成简单介绍
  4. opencv用java完成的例子_SpringBoot整合OpenCV的实现示例
  5. py函数两个返回值_Python 函数为什么会默认返回 None?
  6. Cheat Engine 教程( 1 - 9 通关 )
  7. c 表达式必须是可修改的左值_C++中的左值,右值,左值引用,右值引用
  8. python json转dict(dict转json)
  9. bboss_spring_struts2_myibatis对比分析
  10. anime.js 图片位移动画_打造高大上的Canvas粒子动画
  11. Dubbo源码解析之SPI(一):扩展类的加载过程
  12. LINUX EMOS部署及管理
  13. Java实现:挖金矿问题
  14. casquette swagg:泉州故事
  15. AMD显卡怎么提高帧数?AMD显卡提高fps的方法
  16. 微信公众号如何设置关键词回复Word/Excel/pdf/ppt等文件?
  17. Java基础强化训练——开发工具及输出语句训练
  18. 阿里电话面试之所做所得所感(2015年7月)
  19. FSCapture注册码
  20. 基于RGB-D数据的语义建图

热门文章

  1. 2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛 题解
  2. UE4学习笔记:混合空间(BlendSpace)的使用
  3. 《富豪谷底求生》纪录片记录
  4. 60行代码爬取知乎神回复,笑到停不下来
  5. Stay hungry stay young
  6. 如何在阿里云服务器上搭建mysql服务(最新版)
  7. 2022个人邮箱注册哪个好?163企业邮箱怎么申请注册个人电子邮箱
  8. 光声断层成像的傅里叶变换图像重建算法
  9. Red Team常用命令速查
  10. 工业互联网-企业数据打通解决方案