目录
一、LockSupport
1、park
2、unpark
二、Parker
1、定义
2、Allocate / Release
3、park
4、unpark
三、ParkEvent
1、定义
2、Allocate / Release
3、TryPark / park
4、unpark
Parker是Unsafe类的park和unpark方法的核心,ParkEvent是Thread的sleep方法,synchronized关键字中让线程休眠的核心,本篇博客就详细探讨这两个类的实现细节。
LockSupport是实现Java Lock接口的关键,里面定义的方法都是静态方法,且底层实现都是调用sun.misc.Unsafe的方法,其中大部分都是本地方法,其本地方法实现都在hotspot\src\share\vm\prims\Unsafe.cpp中,并不是在正常的jdk\src\share\native目录下,其本地方法的注册通过JVM_RegisterUnsafeMethods方法实现,对应于Unsafe类的静态registerNatives本地方法,即当Unsafe类加载的时候就会通过上述方法完成Unsafe类中其他本地方法的注册。
park类方法有多个版本,如下:
其用途都是让某个线程处于阻塞(休眠)状态,操作系统不会再给该线程分配CPU时间片,其实现如下:
public static void park() {
UNSAFE.park(false, 0L);
}
//跟park相比就是parkBlocker不一样
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
private static void setBlocker(Thread t, Object arg) {
//将arg写入Thread的parkBlocker属性,该属性是包内访问的
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
//跟park相比增加了阻塞的时间限制,单位是纳秒
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
public static void parkNanos(Object blocker, long nanos) {
if (nanos > 0) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, nanos);
setBlocker(t, null);
}
}
//单位是毫秒
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
UnSafe类的putObject和park方法都是本地方法,其实现如下:
//putObject的实现
UNSAFE_ENTRY(void, Unsafe_SetObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h))
UnsafeWrapper("Unsafe_SetObject");
//x_h就是参数Object arg
oop x = JNIHandles::resolve(x_h);
//obj实际就是参数Thread t
oop p = JNIHandles::resolve(obj);
//index_oop_from_field_offset_long方法获取保存该属性的地址,oop_store负责将x写入该地址
if (UseCompressedOops) {
oop_store((narrowOop*)index_oop_from_field_offset_long(p, offset), x);
} else {
oop_store((oop*)index_oop_from_field_offset_long(p, offset), x);
}
UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
UnsafeWrapper("Unsafe_Park");
EventThreadPark event;
JavaThreadParkedState jtps(thread, time != 0);
//获取parker,让当前线程休眠
thread->parker()->park(isAbsolute != 0, time);
if (event.should_commit()) {
//发布事件
oop obj = thread->current_park_blocker();
event.set_klass((obj != NULL) ? obj->klass() : NULL);
event.set_timeout(time);
event.set_address((obj != NULL) ? (TYPE_ADDRESS) cast_from_oop(obj) : 0);
event.commit();
}
UNSAFE_END
JavaThreadParkedState通过构造方法和析构方法来修改线程的状态,并记录锁等待的次数和耗时,其实现如下:
unpark方法只有一个版本,注意unpark不一定对当前线程,也可能是其他某个线程,其实现如下:
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
Unsafe的unpark方法也是一个本地方法,其实现如下:
UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
UnsafeWrapper("Unsafe_Unpark");
Parker* p = NULL;
if (jthread != NULL) {
//获取关联的Thread实例oop
oop java_thread = JNIHandles::resolve_non_null(jthread);
if (java_thread != NULL) {
//
jlong lp = java_lang_Thread::park_event(java_thread);
if (lp != 0) {
//不为空
p = (Parker*)addr_from_java(lp);
} else {
//如果为空,说明是第一次访问
//获取锁Threads_lock
MutexLocker mu(Threads_lock);
//获取关联的Thread实例oop
java_thread = JNIHandles::resolve_non_null(jthread);
if (java_thread != NULL) {
//获取关联的JavaThread
JavaThread* thr = java_lang_Thread::thread(java_thread);
if (thr != NULL) {
p = thr->parker();
if (p != NULL) {
//设置Thread实例的nativeParkEventPointer属性,这样下次调用unpark方法时可以快速的获取parker指针
java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
}
}
}
}
}
}
if (p != NULL) {
//执行unpark方法唤醒目标线程
p->unpark();
}
UNSAFE_END
jlong java_lang_Thread::park_event(oop java_thread) {
if (_park_event_offset > 0) {
//即获取Thread实例的nativeParkEventPointer属性,该属性是private的,用来保存关联的Parker的指针
return java_thread->long_field(_park_event_offset);
}
return 0;
}
bool java_lang_Thread::set_park_event(oop java_thread, jlong ptr) {
if (_park_event_offset > 0) {
java_thread->long_field_put(_park_event_offset, ptr);
return true;
}
return false;
}
Unsafe_Unpark会将JavaThread的parker属性缓存到Thread实例的nativeParkEventPointer属性中,方便下次调用unpark方法时可以快速获取关联的parker,然后执行unpark方法唤醒目标线程。
Parker的定义在hotspot\src\share\vm\runtime\park.hpp中,继承自os::PlatformParker,其包含的属性如下:
父类PlatformParker包含的属性如下:
Allocate方法会创建一个Parker,主要是线程创建时调用;Release方法会释放一个Parker,主要是线程销毁的时候调用,其调用链如下:
这两方法的实现如下:
Parker * Parker::Allocate (JavaThread * t) {
guarantee (t != NULL, "invariant") ;
Parker * p ;
//获取锁ListLock
Thread::SpinAcquire(&ListLock, "ParkerFreeListAllocate");
{
//获取链表头
p = FreeList;
if (p != NULL) {
//将链表头从链表中移除
FreeList = p->FreeNext;
}
}
//释放锁
Thread::SpinRelease(&ListLock);
if (p != NULL) {
//有空闲的Parker
guarantee (p->AssociatedWith == NULL, "invariant") ;
} else {
//没有空闲的,重新创建一个
p = new Parker() ;
}
//保存关联的线程
p->AssociatedWith = t ; // Associate p with t
p->FreeNext = NULL ;
return p ;
}
void Parker::Release (Parker * p) {
if (p == NULL) return ;
guarantee (p->AssociatedWith != NULL, "invariant") ;
guarantee (p->FreeNext == NULL , "invariant") ;
//关联的线程置为NULL
p->AssociatedWith = NULL ;
//获取锁
Thread::SpinAcquire(&ListLock, "ParkerFreeListRelease");
{
//将p插入到链表头
p->FreeNext = FreeList;
FreeList = p;
}
//释放锁
Thread::SpinRelease(&ListLock);
}
Parker() : PlatformParker() {
_counter = 0 ;
FreeNext = NULL ;
AssociatedWith = NULL ;
}
PlatformParker() {
int status;
//初始化_cond数组和_mutex
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
}
注意Parker是JavaThread的一个实例属性,Unsafe中park和unpark方法都是针对当前线程,即不存在两个不同的线程访问同一个Parker实例的情形,但是存在同一个Parker的park/unpark方法在同一个线程内被多次调用。
park用于让某个线程处于阻塞状态,底层实现是pthread_cond_wait或者pthread_cond_timedwait,其实现如下:
void Parker::park(bool isAbsolute, jlong time) {
//将_counter属性置为0,返回值大于0,说明正在执行unpark动作唤醒当前线程,再park让其休眠无意义
if (Atomic::xchg(0, &_counter) > 0) return;
//获取当前的JavaThread
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
JavaThread *jt = (JavaThread *)thread;
//如果线程已经中断
if (Thread::is_interrupted(thread, false)) {
return;
}
timespec absTime;
if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
if (time > 0) {
//初始化absTime,计算等待到那个时间为止
unpackTime(&absTime, isAbsolute, time);
}
//切换线程状态为_thread_blocked,会检查安全点
ThreadBlockInVM tbivm(jt);
//如果该线程已经中断或者尝试获取锁失败则返回,尝试获取锁失败说明有其他线程占用这个锁
if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
return;
}
int status ;
if (_counter > 0) { //跟一开始的xchg逻辑相同
_counter = 0;
//解锁
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
//让修改立即生效
OrderAccess::fence();
return;
}
//修改线程状态为CONDVAR_WAIT
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
jt->set_suspend_equivalent();
assert(_cur_index == -1, "invariant");
if (time == 0) {
_cur_index = REL_INDEX; // arbitrary choice when not timed
//无期限等待,直到被唤醒
status = pthread_cond_wait (&_cond[_cur_index], _mutex) ;
} else {
_cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
//底层是pthread_cond_timedwait,让当前线程在_mutex上等待指定的时间,如果这段时间范围内被唤醒了则返回0,否则返回非0值
status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;
//WorkAroundNPTLTimedWaitHang的默认值是1
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
//销毁并重新初始化_cur_index对应的_cond
pthread_cond_destroy (&_cond[_cur_index]) ;
pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
}
}
//线程被唤醒了,此时counter会被置为1
_cur_index = -1;
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
status, "cond_timedwait");
//将counter重置为0
_counter = 0 ;
//解锁
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
OrderAccess::fence();
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;
//正常unpark完成counter等于1,park完成counter等于0
_counter = 1;
if (s < 1) {
// thread might be parked
if (_cur_index != -1) {
//WorkAroundNPTLTimedWaitHang默认值为1
if (WorkAroundNPTLTimedWaitHang) {
//发送信号,唤醒目标线程
status = pthread_cond_signal (&_cond[_cur_index]);
assert (status == 0, "invariant");
//解锁
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant");
} else {
int index = _cur_index;
//先解锁
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant");
//再唤醒
status = pthread_cond_signal (&_cond[index]);
assert (status == 0, "invariant");
}
} else {
//_cur_index等于-1,线程从休眠状态被唤醒后就是-1了
pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
}
} else {
//_counter大于或者等于1,说明其已经执行过unpark了,不需要再次唤醒了
pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
}
}
ParkEvent的定义也是在park.hpp中,继承自os::PlatformEvent,其包含的属性如下:
PlatformEvent包含的属性如下:
同Parker,这两方法分别用于分配和销毁一个ParkEvent,其调用链如下:
其实现如下:
ParkEvent * ParkEvent::Allocate (Thread * t) {
ParkEvent * ev ;
//获取锁
Thread::SpinAcquire(&ListLock, "ParkEventFreeListAllocate");
{
//将FreeList链表头从链表中移除
ev = FreeList;
if (ev != NULL) {
FreeList = ev->FreeNext;
}
}
//释放锁
Thread::SpinRelease(&ListLock);
if (ev != NULL) {
//如果找到一个空闲的ParkEvent
guarantee (ev->AssociatedWith == NULL, "invariant") ;
} else {
//如果没有找到,则创建一个
ev = new ParkEvent () ;
guarantee ((intptr_t(ev) & 0xFF) == 0, "invariant") ;
}
//将_Event置为0
ev->reset() ; // courtesy to caller
//保存关联的线程
ev->AssociatedWith = t ; // Associate ev with t
ev->FreeNext = NULL ;
return ev ;
}
void ParkEvent::Release (ParkEvent * ev) {
if (ev == NULL) return ;
guarantee (ev->FreeNext == NULL , "invariant") ;
ev->AssociatedWith = NULL ;
//获取锁
Thread::SpinAcquire(&ListLock, "ParkEventFreeListRelease");
{
//归还到FreeList链表中
ev->FreeNext = FreeList;
FreeList = ev;
}
//释放锁
Thread::SpinRelease(&ListLock);
}
ParkEvent() : PlatformEvent() {
AssociatedWith = NULL ;
FreeNext = NULL ;
ListNext = NULL ;
ListPrev = NULL ;
OnList = 0 ;
TState = 0 ;
Notified = 0 ;
IsWaiting = 0 ;
}
PlatformEvent() {
int status;
//初始化_cond和_mutex
status = pthread_cond_init (_cond, os::Linux::condAttr());
assert_status(status == 0, status, "cond_init");
status = pthread_mutex_init (_mutex, NULL);
assert_status(status == 0, status, "mutex_init");
_Event = 0 ;
_nParked = 0 ;
_Assoc = NULL ;
}
void reset() { _Event = 0 ; }
ParkEvent在JavaThread中也是实例属性,如下:
park用于将某个线程变成阻塞状态,其实现如下:
int os::PlatformEvent::TryPark() {
for (;;) {
const int v = _Event ;
//_Event只能是0或者1
guarantee ((v == 0) || (v == 1), "invariant") ;
//将_Event原子的置为0
if (Atomic::cmpxchg (0, &_Event, v) == v) return v ;
}
}
void os::PlatformEvent::park() { // AKA "down()"
int v ;
for (;;) {
v = _Event ;
//将其原子的减1
if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ;
}
guarantee (v >= 0, "invariant") ;
if (v == 0) {
//获取锁
int status = pthread_mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
guarantee (_nParked == 0, "invariant") ;
//已park线程计数加1
++ _nParked ;
//_Event已经原子的减1,变成-1了
while (_Event < 0) {
//无期限等待
status = pthread_cond_wait(_cond, _mutex);
if (status == ETIME) { status = EINTR; }
assert_status(status == 0 || status == EINTR, status, "cond_wait");
}
//被唤醒了
//计数减1
-- _nParked ;
//重置成0
_Event = 0 ;
//释放锁
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
//让修改立即生效
OrderAccess::fence();
}
guarantee (_Event >= 0, "invariant") ;
}
int os::PlatformEvent::park(jlong millis) {
guarantee (_nParked == 0, "invariant") ;
int v ;
for (;;) {
v = _Event ;
//将其原子的减1
if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ;
}
guarantee (v >= 0, "invariant") ;
if (v != 0) return OS_OK ;
//计算等待的时间
struct timespec abst;
compute_abstime(&abst, millis);
int ret = OS_TIMEOUT;
//获取锁
int status = pthread_mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
guarantee (_nParked == 0, "invariant") ;
//计数加1
++_nParked ;
while (_Event < 0) {
//让线程休眠,底层是pthread_cond_timedwait
status = os::Linux::safe_cond_timedwait(_cond, _mutex, &abst);
//WorkAroundNPTLTimedWaitHang的值默认是1
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy (_cond);
pthread_cond_init (_cond, os::Linux::condAttr()) ;
}
//被中断后就返回EINTR,正常被唤醒就返回0,另外两个是等待超时
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
status, "cond_timedwait");
//FilterSpuriousWakeups默认是true
if (!FilterSpuriousWakeups) break ; // previous semantics
//如果超时了则退出循环
if (status == ETIME || status == ETIMEDOUT) break ;
}
--_nParked ;
if (_Event >= 0) {
ret = OS_OK;
}
_Event = 0 ;
//解锁
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
assert (_nParked == 0, "invariant") ;
//让修改立即生效
OrderAccess::fence();
return ret;
}
unpark用于唤醒某个被park方法阻塞的线程,其实现如下:
void os::PlatformEvent::unpark() {
//将其原子的置为1,如果原来就是1,说明已经unpark过了,直接返回
if (Atomic::xchg(1, &_Event) >= 0) return;
//获取锁
int status = pthread_mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
int AnyWaiters = _nParked;
assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
//WorkAroundNPTLTimedWaitHang默认是true
if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
AnyWaiters = 0;
//发信号唤醒该线程,被唤醒后将_nParked置为0
pthread_cond_signal(_cond);
}
//释放锁
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
if (AnyWaiters != 0) {
//pthread_cond_signal不要求获取锁,此处再次唤醒
status = pthread_cond_signal(_cond);
assert_status(status == 0, status, "cond_signal");
}
}