1-locksupport
文章目录
-
在java中,当需要阻塞或者唤醒一个线程时,都会使用LockSupport工具类来完成相应的工作。LockSupport类中定义了一组公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能。
-
本文基于jdk11的源码来进行解析。
-
方法列表
-
park()阻塞当前线程
-
park() 阻塞 park(Object blocker) 阻塞 parkUntil(long deadline) 阻塞直到deadline parkUntil(Object blocker,long deadline) 阻塞直到deadline parkNanos(long nanos) 阻塞nanos毫秒 parkNanos(Object blocker,long nanos) 阻塞nanos毫秒
-
-
unpark(Thread)解除阻塞的线程
unpark(Thread thread)
解除指定线程的阻塞
-
blocker设置与获取
-
setBlocker(Thread t,Object blocker) 设置指定线程的blocker getBlocker(Thread t) 获取指定线程的blocker
-
-
-
用法
-
工作原理
-
park及带时间的park
-
LockSupport类中的park方法
-
private static final Unsafe U = Unsafe.getUnsafe(); public static void park() { U.park(false, 0L); } public static void parkNanos(long nanos) { if (nanos > 0) U.park(false, nanos); } public static void parkUntil(long deadline) { U.park(true, deadline); }
-
-
park方法调用的Unsafe类代码
-
public native void park(boolean isAbsolute, long time);
-
-
Unsafe类中park对应的jvm源码
-
UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) { HOTSPOT_THREAD_PARK_BEGIN((uintptr_t) thread->parker(), (int) isAbsolute, time); EventThreadPark event; JavaThreadParkedState jtps(thread, time != 0); //根据线程寻找parker thread->parker()->park(isAbsolute != 0, time);//真正的park实现 if (event.should_commit()) { const oop obj = thread->current_park_blocker(); if (time == 0) { post_thread_park_event(&event, obj, min_jlong, min_jlong); } else { if (isAbsolute != 0) { post_thread_park_event(&event, obj, min_jlong, time); } else { post_thread_park_event(&event, obj, time, min_jlong); } } } HOTSPOT_THREAD_PARK_END((uintptr_t) thread->parker()); } UNSAFE_END
-
-
thread->parker()->park(isAbsolute != 0, time);中park的源码
-
void Parker::park(bool isAbsolute, jlong time) { if (Atomic::xchg(0, &_counter) > 0) return;//设置成0失败则直接返回不阻塞 Thread* thread = Thread::current(); JavaThread *jt = (JavaThread *)thread; if (Thread::is_interrupted(thread, false)) {//如果此时被中断,直接返回不阻塞 return; } struct timespec absTime; if (time < 0 || (isAbsolute && time == 0)) { //time设置错误或无需阻塞 return; } if (time > 0) { to_abstime(&absTime, time, isAbsolute);//获取真正阻塞时间 } ThreadBlockInVM tbivm(jt); if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {//中断了或加锁失败直接返回不阻塞 return; } int status; if (_counter > 0) { //counter>0直接返回不阻塞 _counter = 0;//并将counter设置回0 status = pthread_mutex_unlock(_mutex);//解锁 OrderAccess::fence(); return; } OSThreadWaitState osts(thread->osthread(), false); jt->set_suspend_equivalent(); if (time == 0) {//时间=0则为park() _cur_index = REL_INDEX; /*********************************** 调用pthread_cond_wait来等待唤醒 ***********************************/ status = pthread_cond_wait(&_cond[_cur_index], _mutex); assert_status(status == 0, status, "cond_timedwait"); } else {//有阻塞时间限制的parknanos/parkuntil _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX; /*********************************** 调用pthread_cond_timedwait来等待唤醒 ***********************************/ status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime); assert_status(status == 0 || status == ETIMEDOUT, status, "cond_timedwait"); } _cur_index = -1; _counter = 0; status = pthread_mutex_unlock(_mutex);//解锁 //*********** }
- 通过代码可以发现park的阻塞的底层实现是通过pthread的中的pthread_cond_wait以及pthread_cond_timedwait来实现的。
- park为pthread_cond_wait,parkNanos和parkUntil是pthread_cond_timedwait。
-
-
-
unpark
-
LockSupport类中的unpark方法
-
private static final Unsafe U = Unsafe.getUnsafe(); public static void unpark(Thread thread) { if (thread != null) U.unpark(thread); }
-
-
unpark方法调用的Unsafe类代码
-
public native void unpark(Object thread);
-
-
Unsafe类中unpark对应的jvm源码
-
UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) { Parker* p = NULL; if (jthread != NULL) { ThreadsListHandle tlh; JavaThread* thr = NULL; oop java_thread = NULL; (void) tlh.cv_internal_thread_to_JavaThread(jthread, &thr, &java_thread); if (java_thread != NULL) {//java线程有效 //获取java中parker的地址 jlong lp = java_lang_Thread::park_event(java_thread); if (lp != 0) {//java中是否设置了parker p = (Parker*)addr_from_java(lp);//找寻parker } else {//没设置 if (thr != NULL) { p = thr->parker();//找寻parker if (p != NULL) { java_lang_Thread::set_park_event(java_thread, addr_to_java(p)); } } } } } if (p != NULL) { HOTSPOT_THREAD_UNPARK((uintptr_t) p); /*********************************** 真正的unpark调用 ***********************************/ p->unpark(); } } UNSAFE_END
-
-
p->unpark()中unpark的源码
-
void Parker::unpark() { int status = pthread_mutex_lock(_mutex);//加锁 const int s = _counter; _counter = 1;//设置counter为1 int index = _cur_index; status = pthread_mutex_unlock(_mutex);//解锁 if (s < 1 && index != -1) { /*********************************** 调用pthread_cond_signal来唤醒此线程 ***********************************/ status = pthread_cond_signal(&_cond[index]); } }
-
因为unpark传入了需要唤醒的指定线程,而通过此线程获取到了这个线程的parker来通过pthread_cond_signal唤醒。
-
-
-
park/unpark总结
-
pthread方法
-
mutex
-
在park和unpark中使用了 pthread_mutex_trylock、pthread_mutex_lock加锁与pthread_mutex_unlock解锁。
-
pthread_mutex_init 初始化一个mutex pthread_mutex_lock 加锁(阻塞直到加索成功) pthread_mutex_trylock 尝试一次加索(不阻塞) pthread_mutex_unlock 解锁
-
-
conditiion
-
在park系列方法中调用了pthread_cond_wait以及pthread_cond_timedwait,unpark调用了pthread_cond_signal。
-
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr) 创建一个condition的内核变量 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex) 等待内核变量变为signaled int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime) 在指定时间内等待内核变量变为signaled int pthread_cond_signal(pthread_cond_t *cond) 把内核变量置为signaled,随机激活一个等待的线程 -
一个线程有一个Parker类(C++)实例,一个park实例自己初始化自己的condition内核变量,因此在调用pthread_cond_signal时可以唤醒唯一的线程,因为一个condition对应一个线程。
-
-
-