LockSupport
concurrent包是基于AQS (AbstractQueuedSynchronizer)框架的,AQS框架借助于两个类:
- Unsafe(提供CAS操作)
- LockSupport(提供park/unpark操作,底层仍然调用是Unsafe类的park/unpark方法)
因此,LockSupport非常重要。先看一下park和unpark方法怎么用的吧。
示例:
public static void main(String[] args) throws Exception {
Thread thread = new Thread(() -> {
System.out.println("开始睡眠...");
// 开始睡眠
LockSupport.park();
System.out.println("已被唤醒!");
});
thread.start();
Thread.sleep(1000);
System.out.println("睡了1秒钟之后开始唤醒...");
// 开始唤醒
LockSupport.unpark(thread);
}
输出:
开始睡眠... 睡了1秒钟之后开始唤醒... 已被唤醒!
从示例中,我们大概就能明白park和unpark方法的作用,park方法类似于wait,unpark方法类似于notify。下面我们再看一下复杂一点的示例,来深刻理解park和unpark方法的作用。
二、底层原理
LockSupport类park方法和unpark方法
public static void park() {
UNSAFE.park(false, 0L);
}
// ...
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
Unsafe.park和Unsafe.unpark的底层实现原理
public native void park(boolean isAbsolute, long time); public native void unpark(Object var1);
每个Java线程都有一个Parker实例,Parker类是这样定义的:
class Parker : public os::PlatformParker {
private:
volatile int _counter ;
...
public:
void park(bool isAbsolute, jlong time);
void unpark();
...
}
class PlatformParker : public CHeapObj<mtInternal> {
protected:
pthread_mutex_t _mutex [1] ;
pthread_cond_t _cond [1] ;
...
}
可以看到Parker类实际上用Posix的mutex(),condition来实现的。mutex是操作系统函数,Synchronized底层也是调用mutex互斥锁的。
在Parker类里的_counter字段,就是用来记录“许可”的。
park过程
当调用park时,先尝试能否直接拿到“许可”,即_counter>0时,如果成功,则把_counter设置为0,并返回:
void Parker::park(bool isAbsolute, jlong time) {
// Ideally we'd do something useful while spinning, such
// as calling unpackTime().
// Optional fast-path check:
// Return immediately if a permit is available.
// We depend on Atomic::xchg() having full barrier semantics
// since we are doing a lock-free update to _counter.
if (Atomic::xchg(0, &_counter) > 0) return;
如果不成功,则构造一个ThreadBlockInVM,然后检查_counter是不是>0,如果是,则把_counter设置为0,unlock <wiz_tmp_highlight_tag class="cm-searching">mutex并返回:
ThreadBlockInVM tbivm(jt);
if (_counter > 0) { // no wait needed
_counter = 0;
status = pthread_mutex_unlock(_mutex);
否则,再判断等待的时间,然后再调用pthread_cond_wait函数等待,如果等待返回,则把_counter设置为0,unlock <wiz_tmp_highlight_tag class="cm-searching">mutex并返回:
if (time == 0) {
status = pthread_cond_wait (_cond, _mutex) ;
}
_counter = 0 ;
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
OrderAccess::fence();
unpark过程
当unpark时,则简单多了,直接设置_counter为1,再unlock <wiz_tmp_highlight_tag class="cm-searching">mutex返回。如果_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") ;
}
}

浙公网安备 33010602011771号