温故知新-多线程-深入刨析park、unpark
- Posted by 微博@Yangsc_o
- 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
摘要
本文主要介绍park、unpark的功能以及hotspot实现原理,为下一篇介绍ReentrantLock做铺垫!
park、unpark
LockSupport类是Java6引入的一个类,提供了基本的线程同步原语。LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,两个函数但为上层提供了强大的同步原语。
public native void unpark(Thread jthread);
public native void park(boolean isAbsolute, long time);
// isAbsolute参数是指明时间是绝对的,还是相对的。
unpark函数为线程提供“许可(permit)”,线程调用park函数则等待“许可”。这个有点像信号量,但是这个“许可”是不能叠加的,“许可”是一次性的。
比如线程B连续调用了三次unpark函数,当线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态。
看一下hotspot实现
在Parker类里的_counter字段,就是用来记录所谓的“许可”的。
位置:hotspot/src/share/vm/runtime/park.hpp
简化代码如下
class Parker : public os::PlatformParker {
private:
volatile int _counter ;
Parker * FreeNext ;
JavaThread * AssociatedWith ; // Current association
public:
Parker() : PlatformParker() {
_counter = 0 ;
FreeNext = NULL ;
AssociatedWith = NULL ;
}
public:
// For simplicity of interface with Java, all forms of park (indefinite,
// relative, and absolute) are multiplexed into one call.
void park(bool isAbsolute, jlong time);
void unpark();
};
park
简化代码如下:当调用park时,先尝试直接能否直接拿到“许可”,即_counter>0时,如果成功,则把_counter设置为0,并返回;
如果不成功,则构造一个ThreadBlockInVM,然后检查_counter是不是>0,如果是,则把_counter设置为0,unlock mutex并返回;
Java dos里提到,当下面三种情况下park函数会返回,在这段代码里也可以体现;
Some other thread invokes unpark with the current thread as the target; or
Some other thread interrupts the current thread; or
The call spuriously (that is, for no reason) returns.
void Parker::park(bool isAbsolute, jlong time) {
if (Atomic::xchg(0, &_counter) > 0) return;
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
JavaThread *jt = (JavaThread *)thread;
if (Thread::is_interrupted(thread, false)) {
return;
}
// Next, demultiplex/decode time arguments
struct timespec absTime;
if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
if (time > 0) {
unpackTime(&absTime, isAbsolute, time);
}
...
if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
return;
}
int status ;
if (_counter > 0) { // no wait needed
_counter = 0;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
// Paranoia to ensure our locked and lock-free paths interact
// correctly with each other and Java-level accesses.
OrderAccess::fence();
return;
}
- unpark
unpark时,设置_counter为1;如果_counter = 1,unlock mutext返回。如果_counter=0,需要调用pthread_cond_signal唤醒在park中等待的线程:
void Parker::unpark() {
int s, status ;
status = pthread_mutex_lock(_mutex);
assert (status == 0, "invariant") ;
s = _counter;
_counter = 1;
if (s < 1) {
if (WorkAroundNPTLTimedWaitHang) {
status = pthread_cond_signal (_cond) ;
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) ;
assert (status == 0, "invariant") ;
}
} else {
pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
}
}
自此park、unpark已经分析完毕;
参考
你的鼓励也是我创作的动力
温故知新-多线程-深入刨析park、unpark的更多相关文章
- 温故知新-多线程-深入刨析volatile关键词
文章目录 摘要 volatile的作用 volatile如何解决线程可见? CPU Cache CPU Cache & 主内存 缓存一致性协议 volatile如何解决指令重排序? volat ...
- 温故知新-多线程-深入刨析CAS
文章目录 摘要 CAS是什么? CAS是如何实现的? CAS存在的问题? 你的鼓励也是我创作的动力 Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 ...
- 温故知新-多线程-深入刨析synchronized
Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 文章目录 摘要 synchroniz ...
- JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
一.前言 在多线程的场景下,我们会经常使用加锁,来保证线程安全.如果锁用的不好,就会陷入死锁,我们以前可以使用Object的wait/notify来解决死锁问题.也可以使用Condition的awai ...
- Orchard 刨析:Logging
最近事情比较多,有预研的,有目前正在研发的,都是很需要时间的工作,所以导致这周只写了两篇Orchard系列的文章,这边不能保证后期会很频繁的更新该系列,但我会写完这整个系列,包括后面会把正在研发的东西 ...
- Orchard 刨析:Caching
关于Orchard中的Caching组件已经有一些文章做了介绍,为了系列的完整性会再次对Caching组件进行一次介绍. 缓存的使用 在Orchard看到如下一段代码: 可以看到使用缓存的方法Get而 ...
- Orchard 刨析:导航篇
之前承诺过针对Orchard Framework写一个系列.本应该在昨天写下这篇导航篇,不过昨天比较累偷懒的去玩了两盘单机游戏哈哈.下面进入正题. 写在前面 面向读者 之前和本文一再以Orchard ...
- Learning Cocos2d-x for WP8(2)——深入刨析Hello World
原文:Learning Cocos2d-x for WP8(2)--深入刨析Hello World cocos2d-x框架 在兄弟篇Learning Cocos2d-x for XNA(1)——小窥c ...
- 实现两线程的同步二(lockSupport的park/unpark)
1.使用LockSupport的part/unpark实现 package com.ares.thread; import java.util.concurrent.locks.LockSupport ...
随机推荐
- Docker 部署Spring Boot 项目并连接mysql、redis容器(记录过程)
Spring Boot 项目配置 将写好的Spring Boot 项目通过maven 进行package打包获得可执行Jar 再src/main/docker(放哪都行)下编写创建Dockerfile ...
- search(16)- elastic4s-内嵌文件:nested and join
从SQL领域来的用户,对于ES的文件关系维护方式会感到很不习惯.毕竟,ES是分布式数据库只能高效处理独个扁平类型文件,无法支持关系式数据库那样的文件拼接.但是,任何数据库应用都无法避免树型文件关系,因 ...
- CF1013D Chemical table
题目链接:http://codeforces.com/contest/1013/problem/D 题目大意: 给出一个 \(n \times m\) 的表格,表格上有一些初始点.若有这样的三个点:\ ...
- Verilog代码和FPGA硬件的映射关系(一)
代码和硬件之间的映射关系是一个很奇妙的过程,也展现出人类的智慧.单片机内部的硬件结构都是固定的,无法改变,我们通过代码操作着寄存器的读写,来执行各种复杂的任务.FPGA的硬件结构并不像单片机一样是固定 ...
- 【SocketIoClientDotNet】Nuget包安装问题
问题: Nuget安装[SocketIoClientDotNet]失败 错误信息: Operation failed Expected 1 export(s) with contract name & ...
- zsh 使用通配符功能
zsh 使用通配符功能 默认情况下 zsh 是不支持通配符 (*) 匹配的: 第一步,打开zsh配置文件 $ vi .zshrc 第二步,最后一行添加下面语句到文本中,保存.退出: setopt no ...
- 10 个提高效率的 Linux 命令别名
在 Linux 环境下工作的工程师,一定会对那些繁琐的指令和参数命令行印象深刻吧.而且,可怕的不是繁琐,而是需要大量重复输入这些繁琐的命令. 在 Linux 下我们有个别名命令 alias ,可以将那 ...
- 【Java8新特性】关于Java8中的日期时间API,你需要掌握这些!!
写在前面 Java8之前的日期和时间API,存在一些问题,比如:线程安全的问题,跨年的问题等等.这些问题都在Hava8中的日期和时间API中得到了解决,而且Java8中的日期和时间API更加强大.立志 ...
- 一篇文章看清楚 Linux 的职业发展方向
手机.汽车.甚至宇宙飞船,在今天的科技世界中,你几乎到处都能看到 Linux 的身影.前两天 SpaceX 成功将宇航员送入太空的猎鹰9号火箭与龙飞船用的也是 Linux的操作系统.身处与 Linux ...
- Rocket - debug - TLDebugModuleInner - DMSTATUS
https://mp.weixin.qq.com/s/GyGriFyeq_7Z3xOjKn56Mg 简单介绍TLDebugModuleInner中DMSTATUS寄存器的实现. 1. DMSTATUS ...