AQS是java.conccurent包下諸多工具類的抽象基類,借以AQS抽象基類,實(shí)現(xiàn)如lock,unlock,condition.wait,condition.signal等重要功能。
其中ReentrantLock(可重入鎖)就是借以AQS實(shí)現(xiàn)加鎖,釋放鎖,線程阻塞,線程喚醒等功能。
對(duì)于獨(dú)占式(Exclusive)
lock()->acquire()--->tryAcquire()[模板方法]
|---->acquireQueued(addWaiter())
unlock()->release()--->tryRelease()[模板方法]
對(duì)于共享式(Shard)
lock()->acquireShard()->tryAcquireShard()[模板方法]
unlock()->releaseShard()->tryReleaseShard()[模板方法]
在獨(dú)占式模式下,在線程A獲取鎖后,線程B也來(lái)?yè)屨兼i,但是此時(shí)線程A占有著鎖,線程B就會(huì)加入AQS的雙向鏈表中,在條件滿足的情況下(前驅(qū)節(jié)點(diǎn)有waitStatus < 0存在)就會(huì)進(jìn)行阻塞。
LockSupport.park()
AbstractQueuedSynchronizer中的shouldParkAfterFailedAcquire(..)方法判斷是否滿足阻塞條件
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
線程調(diào)用LockSupport.park()阻塞線程
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); // 記錄線程對(duì)象
UNSAFE.park(false, 0L);
setBlocker(t, null); // 記錄線程對(duì)象
}
調(diào)用UNSAFE.park(false, 0L);查看此方法已經(jīng)變成了本地方法
public native void park(boolean var1, long var2);
找到/hotspot/src/share/vm/prims/unsafe.cpp
UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
UnsafeWrapper("Unsafe_Park");
EventThreadPark event;
#ifndef USDT2
HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time);
#else /* USDT2 */
HOTSPOT_THREAD_PARK_BEGIN(
(uintptr_t) thread->parker(), (int) isAbsolute, time);
#endif /* USDT2 */
JavaThreadParkedState jtps(thread, time != 0);
// 調(diào)用thread對(duì)象下的parker下的park()方法
thread->parker()->park(isAbsolute != 0, time);
#ifndef USDT2
HS_DTRACE_PROBE1(hotspot, thread__park__end, thread->parker());
#else /* USDT2 */
HOTSPOT_THREAD_PARK_END(
(uintptr_t) thread->parker());
#endif /* USDT2 */
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<uintptr_t>(obj) : 0);
event.commit();
}
UNSAFE_END
找到\hotspot\src\share\vm\runtime\thread.cpp,\hotspot\src\share\vm\runtime\thread.hpp
通過(guò)thread對(duì)象下的parker函數(shù)返回parker對(duì)象
// JSR166 per-thread parker
private:
Parker* _parker;
public:
Parker* parker() { return _parker; }
\hotspot\src\share\vm\runtime\park.hpp,對(duì)應(yīng)的Parker類
class Parker : public os::PlatformParker {
private:
volatile int _counter ; //計(jì)數(shù)
Parker * FreeNext ; //指向下一個(gè)Parker
JavaThread * AssociatedWith ; // 指向parker所屬的線程。
public:
Parker() : PlatformParker() {
_counter = 0 ; //初始化為0
FreeNext = NULL ;
AssociatedWith = NULL ;
}
protected:
~Parker() { ShouldNotReachHere(); }
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();
// Lifecycle operators
static Parker * Allocate (JavaThread * t) ;
static void Release (Parker * e) ;
private:
static Parker * volatile FreeList ;
static volatile int ListLock ;
};
最終調(diào)用到Parker類的park函數(shù),Parker繼承了PlatformParker。
class PlatformParker : public CHeapObj<mtInternal> {
protected:
enum {
REL_INDEX = 0,
ABS_INDEX = 1
};
int _cur_index; // 條件變量數(shù)組下標(biāo),which cond is in use: -1, 0, 1
pthread_mutex_t _mutex [1] ; //pthread互斥鎖
pthread_cond_t _cond [2] ; // pthread條件變量數(shù)組,一個(gè)用于相對(duì)時(shí)間,一個(gè)用于絕對(duì)時(shí)間。
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
}
};
PlatformParker主要看三個(gè)成員變量,_cur_index, _mutex, _cond。其中mutex和cond就是很熟悉的glibc nptl包中符合posix標(biāo)準(zhǔn)的線程同步工具,一個(gè)互斥鎖一個(gè)條件變量。再看thread和Parker的關(guān)系,在hotspot的Thread類的NameThread內(nèi)部類中有一個(gè) Parker成員變量。說(shuō)明parker是線程變量,在創(chuàng)建線程的時(shí)候就會(huì)生成一個(gè)parker實(shí)例。
以\hotspot\src\os\linux\vm\os_linux.cpp為例,再看park()實(shí)現(xiàn)
void Parker::park(bool isAbsolute, jlong time) {
//原子交換,如果_counter > 0,則將_counter置為0,直接返回,否則_counter為0
if (Atomic::xchg(0, &_counter) > 0) return;
//獲取當(dāng)前線程
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
//下轉(zhuǎn)型為java線程
JavaThread *jt = (JavaThread *)thread;
//如果當(dāng)前線程設(shè)置了中斷標(biāo)志,調(diào)用park則直接返回,所以如果在park之前調(diào)用了
//interrupt就會(huì)直接返回
if (Thread::is_interrupted(thread, false)) {
return;
}
// 高精度絕對(duì)時(shí)間變量
timespec absTime;
//如果time小于0,或者isAbsolute是true并且time等于0則直接返回
if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
//如果time大于0,則根據(jù)是否是高精度定時(shí)計(jì)算定時(shí)時(shí)間
if (time > 0) {
unpackTime(&absTime, isAbsolute, time);
}
//進(jìn)入安全點(diǎn)避免死鎖
// Enter safepoint region
// Beware of deadlocks such as 6317397.
// The per-thread Parker:: mutex is a classic leaf-lock.
// In particular a thread must never block on the Threads_lock while
// holding the Parker:: mutex. If safepoints are pending both the
// the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
ThreadBlockInVM tbivm(jt);
//如果當(dāng)前線程設(shè)置了中斷標(biāo)志,或者獲取mutex互斥鎖失敗則直接返回
//由于Parker是每個(gè)線程都有的,所以_counter cond mutex都是每個(gè)線程都有的,
//不是所有線程共享的所以加鎖失敗只有兩種情況,第一unpark已經(jīng)加鎖這時(shí)只需要返回即可,
//第二調(diào)用pthread_mutex_trylock出錯(cuò)。對(duì)于第一種情況就類似是unpark先調(diào)用的情況,所以
//直接返回。
if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
return;
}
int status ;
//如果_counter大于0,說(shuō)明unpark已經(jīng)調(diào)用完成了將_counter置為了1,
//現(xiàn)在只需將_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,說(shuō)明是相對(duì)時(shí)間也就是isAbsolute是fasle(否則前面就直接返回了),則直接掛起
if (time == 0) {
_cur_index = REL_INDEX; // arbitrary choice when not timed
status = 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;
//使用條件變量使得當(dāng)前線程掛起。
status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;
//如果掛起失敗則銷毀當(dāng)前的條件變量重新初始化。
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy (&_cond[_cur_index]) ;
pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
}
}
//如果pthread_cond_wait成功則以下代碼都是線程被喚醒后執(zhí)行的。
_cur_index = -1;
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
status, "cond_timedwait");
#ifdef ASSERT
pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
#endif
//將_counter變量重新置為1
_counter = 0 ;
//解鎖
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
// 使用內(nèi)存屏障使_counter對(duì)其它線程可見
OrderAccess::fence();
// 如果在park線程掛起的時(shí)候調(diào)用了stop或者suspend則還需要將線程掛起不能返回
if (jt->handle_special_suspend_equivalent_condition()) {
jt->java_suspend_self();
}
}
其中:
/**加鎖**/
pthread\nptl\pthread_mutex_trylock.c
(..),該函數(shù)表示,用來(lái)鎖住mutex 所指定的互斥體,但不阻塞。如果該互斥體已經(jīng)被上鎖,該調(diào)用不會(huì)阻塞等待,而會(huì)返回一個(gè)錯(cuò)誤代碼。
/**休眠**/
pthread_cond_wait(..)
/**解鎖**/
pthread_mutex_unlock(..)