Thread类源码剖析
目錄
1.引子
2.JVM線程狀態(tài)
3.Thread常用方法
4.拓展點(diǎn)
?
?
一、引子
說來(lái)也有些汗顏,搞了幾年java,忽然發(fā)現(xiàn)竟然沒拜讀過java.lang.Thread類源碼,這次特地拿出來(lái)曬一曬。本文將剖析Thread類源碼(本文后面源碼全部默認(rèn)JDK8),并講解一些重要的拓展點(diǎn)。希望對(duì)大家能有一些幫助。
本文講解主干全部出自源碼和注釋,保證了權(quán)威性。(注意:網(wǎng)上,某些書中很多觀點(diǎn)都是錯(cuò)的,過時(shí)的,片面的,所以大家一定要看源碼,重要事情說N遍,看源碼!看源碼!看源碼......)
二、JVM線程狀態(tài)
在正式學(xué)習(xí)Thread類中的具體方法之前,我們先來(lái)了解一下線程有哪些狀態(tài),這個(gè)將會(huì)有助于后面對(duì)Thread類中的方法的理解。
自JDK5開始,線程包括以下6個(gè)狀態(tài),摘自Thread.State:
1 /**2 * A thread state. A thread can be in one of the following states:3 * <ul>4 * <li>{@link #NEW}<br>5 * A thread that has not yet started is in this state.6 * </li>7 * <li>{@link #RUNNABLE}<br>8 * A thread executing in the Java virtual machine is in this state.9 * </li> 10 * <li>{@link #BLOCKED}<br> 11 * A thread that is blocked waiting for a monitor lock 12 * is in this state. 13 * </li> 14 * <li>{@link #WAITING}<br> 15 * A thread that is waiting indefinitely for another thread to 16 * perform a particular action is in this state. 17 * </li> 18 * <li>{@link #TIMED_WAITING}<br> 19 * A thread that is waiting for another thread to perform an action 20 * for up to a specified waiting time is in this state. 21 * </li> 22 * <li>{@link #TERMINATED}<br> 23 * A thread that has exited is in this state. 24 * </li> 25 * </ul> 26 * 27 * <p> 28 * A thread can be in only one state at a given point in time.----》JVM中的線程必須只能是以上6種狀態(tài)的一種。這些狀態(tài)是JVM狀態(tài)并不能和操作系統(tǒng)線程狀態(tài)互相映射。 29 * These states are virtual machine states which do not reflect 30 * any operating system thread states. 31 * 32 * @since 1.5 33 * @see #getState 34 */ 35 public enum State { 36 /** 37 * Thread state for a thread which has not yet started. 38 */ 39 NEW,--->線程剛創(chuàng)建,還未執(zhí)行(start方法) 40 41 /** 42 * Thread state for a runnable thread. A thread in the runnable 43 * state is executing in the Java virtual machine but it may 44 * be waiting for other resources from the operating system 45 * such as processor. 46 */ 47 RUNNABLE,--->已就緒可運(yùn)行的狀態(tài)。處于此狀態(tài)的線程是正在JVM中運(yùn)行的,但可能在等待操作系統(tǒng)級(jí)別的資源,例如CPU時(shí)間片 48 49 /** 50 * Thread state for a thread blocked waiting for a monitor lock. 51 * A thread in the blocked state is waiting for a monitor lock 52 * to enter a synchronized block/method or 53 * reenter a synchronized block/method after calling 54 * {@link Object#wait() Object.wait}. 55 */ 56 BLOCKED,--->阻塞等待監(jiān)視器鎖。處于此狀態(tài)的線程正在阻塞等待監(jiān)視器鎖,以進(jìn)入一個(gè)同步塊/方法,或者在執(zhí)行完wait()方法后重入同步塊/方法。 57 58 /** 59 * Thread state for a waiting thread. 60 * A thread is in the waiting state due to calling one of the 61 * following methods: 62 * <ul> 63 * <li>{@link Object#wait() Object.wait} with no timeout</li> 64 * <li>{@link #join() Thread.join} with no timeout</li> 65 * <li>{@link LockSupport#park() LockSupport.park}</li> 66 * </ul> 67 * 68 * <p>A thread in the waiting state is waiting for another thread to 69 * perform a particular action. 70 * 71 * For example, a thread that has called <tt>Object.wait()</tt> 72 * on an object is waiting for another thread to call 73 * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on 74 * that object. A thread that has called <tt>Thread.join()</tt> 75 * is waiting for a specified thread to terminate. 76 */ 77 WAITING,--->等待。執(zhí)行完Object.wait無(wú)超時(shí)參數(shù)操作,或者 Thread.join無(wú)超時(shí)參數(shù)操作(進(jìn)入等待指定的線程執(zhí)行結(jié)束),或者 LockSupport.park操作后,線程進(jìn)入等待狀態(tài)。一般在等待狀態(tài)的線程在等待其它線程執(zhí)行特殊操作,例如:等待另其它線程操作Object.notify()喚醒或者Object.notifyAll()喚醒所有。 78 79 /** 80 * Thread state for a waiting thread with a specified waiting time. 81 * A thread is in the timed waiting state due to calling one of 82 * the following methods with a specified positive waiting time: 83 * <ul> 84 * <li>{@link #sleep Thread.sleep}</li> 85 * <li>{@link Object#wait(long) Object.wait} with timeout</li> 86 * <li>{@link #join(long) Thread.join} with timeout</li> 87 * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> 88 * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> 89 * </ul> 90 */ 91 TIMED_WAITING,--->限時(shí)等待。Thread.sleep、Object.wait帶超時(shí)時(shí)間、Thread.join帶超時(shí)時(shí)間、LockSupport.parkNanos、LockSupport.parkUntil這些操作會(huì)時(shí)線程進(jìn)入限時(shí)等待。 92 93 /** 94 * Thread state for a terminated thread. 95 * The thread has completed execution. 96 */ 97 TERMINATED;--->終止,線程執(zhí)行完畢。 98 }看了源碼6種狀態(tài),很多人會(huì)迷惑怎么沒有Running狀態(tài)呢?好吧,請(qǐng)相信源碼,不要混淆操作系統(tǒng)線程狀態(tài)和java線程狀態(tài)。JVM中的線程必須只能是以上6種狀態(tài)的一種!(見上圖枚舉State 注釋中的紅色部分)。
Running其實(shí)是早期操作系統(tǒng)下“單線程進(jìn)程”的狀態(tài),如下圖:
?注意:上圖已年久失修,不可參考!!!!
好吧,現(xiàn)在是不是覺得三觀被顛覆...
最新JAVA(JVM)線程狀態(tài)轉(zhuǎn)換如下圖:
?
如上圖,可見:RUNNABLE = 正在JVM中運(yùn)行的(Running)+ 可能在等待操作系統(tǒng)級(jí)別的資源(Ready),例如CPU時(shí)間片
線程創(chuàng)建之后,不會(huì)立即進(jìn)入就緒狀態(tài),因?yàn)榫€程的運(yùn)行需要一些條件(比如內(nèi)存資源),只有線程運(yùn)行需要的所有條件滿足了,才進(jìn)入就緒狀態(tài)。
當(dāng)線程進(jìn)入就緒狀態(tài)后,不代表立刻就能獲取CPU執(zhí)行時(shí)間,也許此時(shí)CPU正在執(zhí)行其他的事情,因此它要等待。當(dāng)?shù)玫紺PU執(zhí)行時(shí)間之后,線程便真正進(jìn)入運(yùn)行狀態(tài)。
線程在運(yùn)行狀態(tài)過程中,可能有多個(gè)原因?qū)е庐?dāng)前線程不繼續(xù)運(yùn)行下去,比如用戶主動(dòng)讓線程睡眠(睡眠一定的時(shí)間之后再重新執(zhí)行)、用戶主動(dòng)讓線程等待,或者被同步塊給阻塞,此時(shí)就對(duì)應(yīng)著多個(gè)狀態(tài):time waiting(睡眠或等待一定的事件)、waiting(等待被喚醒)、blocked(阻塞)。
當(dāng)由于突然中斷或者子任務(wù)執(zhí)行完畢,線程就會(huì)被消亡。
三.Thread類中的方法
老規(guī)矩,先看源碼注釋:
+ View Code
?
Thread類實(shí)現(xiàn)了Runnable接口,在Thread類中,
關(guān)鍵屬性:
name是表示Thread的名字,可以通過Thread類的構(gòu)造器中的參數(shù)來(lái)指定線程名字,
priority表示線程的優(yōu)先級(jí)(最大值為10,最小值為1,默認(rèn)值為5),
daemon表示線程是否是守護(hù)線程,如果在main線程中創(chuàng)建了一個(gè)守護(hù)線程,當(dāng)main方法運(yùn)行完畢之后,守護(hù)線程也會(huì)隨著消亡。在JVM中,垃圾收集器線程就是守護(hù)線程。
target表示要執(zhí)行的任務(wù)。
group線程群組
關(guān)鍵方法:
以下是關(guān)系到線程運(yùn)行狀態(tài)的幾個(gè)方法:
1)start
start()用來(lái)啟動(dòng)一個(gè)線程,當(dāng)調(diào)用start方法后,系統(tǒng)才會(huì)開啟一個(gè)新的線程來(lái)執(zhí)行用戶定義的子任務(wù),在這個(gè)過程中,會(huì)為相應(yīng)的線程分配需要的資源。
2)run
run()方法是不需要用戶來(lái)調(diào)用的,當(dāng)通過start方法啟動(dòng)一個(gè)線程之后,當(dāng)線程獲得了CPU執(zhí)行時(shí)間,便進(jìn)入run方法體去執(zhí)行具體的任務(wù)。注意,繼承Thread類必須重寫run方法,在run方法中定義具體要執(zhí)行的任務(wù)。
3)sleep
sleep方法有兩個(gè)重載版本:
1 public static native void sleep(long millis) throws InterruptedException; 2 3 public static void sleep(long millis, int nanos) throws InterruptedException;sleep讓線程睡眠,交出CPU,讓CPU去執(zhí)行其他的任務(wù)。sleep方法不會(huì)釋放鎖,也就是說如果當(dāng)前線程持有對(duì)某個(gè)對(duì)象的鎖,則即使調(diào)用sleep方法,其他線程也無(wú)法訪問這個(gè)對(duì)象。sleep方法相當(dāng)于讓線程進(jìn)入阻塞狀態(tài)。
4)yield
調(diào)用yield方法會(huì)讓當(dāng)前線程交出CPU權(quán)限,讓CPU去執(zhí)行其他的線程。它跟sleep方法類似,同樣不會(huì)釋放鎖。但是yield不能控制具體的交出CPU的時(shí)間,另外,yield方法只能讓擁有相同優(yōu)先級(jí)的線程有獲取CPU執(zhí)行時(shí)間的機(jī)會(huì)。
注意,調(diào)用yield方法并不會(huì)讓線程進(jìn)入阻塞狀態(tài),而是讓線程重回就緒狀態(tài),它只需要等待重新獲取CPU執(zhí)行時(shí)間,這一點(diǎn)是和sleep方法不一樣的。
5)join
join方法有三個(gè)重載版本:
1 join() 2 join(long millis) //參數(shù)為毫秒 3 join(long millis,int nanoseconds) //第一參數(shù)為毫秒,第二個(gè)參數(shù)為納秒可以看出,當(dāng)調(diào)用thread.join()方法后,main線程會(huì)進(jìn)入等待,然后等待thread執(zhí)行完之后再繼續(xù)執(zhí)行。
實(shí)際上調(diào)用join方法是調(diào)用了Object的wait方法,這個(gè)可以通過查看源碼得知:
wait方法會(huì)讓線程進(jìn)入阻塞狀態(tài),并且會(huì)釋放線程占有的鎖,并交出CPU執(zhí)行權(quán)限。
6)interrupt
interrupt,中斷。單獨(dú)調(diào)用interrupt方法可以使得處于阻塞狀態(tài)的線程拋出一個(gè)異常,也就說,它可以用來(lái)中斷一個(gè)正處于阻塞狀態(tài)的線程;
7)stop
stop方法已經(jīng)是一個(gè)廢棄的方法,它是一個(gè)不安全的方法。因?yàn)檎{(diào)用stop方法會(huì)直接終止run方法的調(diào)用,并且會(huì)拋出一個(gè)ThreadDeath錯(cuò)誤,如果線程持有某個(gè)對(duì)象鎖的話,會(huì)完全釋放鎖,導(dǎo)致對(duì)象狀態(tài)不一致。所以stop方法基本是不會(huì)被用到的。
8)destroy
destroy方法也是廢棄的方法。基本不會(huì)被使用到。
四、拓展點(diǎn)
1.LookSupport.park()和unpark()原理
LockSupport類是Java6(JSR166-JUC)引入的一個(gè)類,提供了基本的線程同步原語(yǔ)。LockSupport實(shí)際上是調(diào)用了Unsafe類里的函數(shù),歸結(jié)到Unsafe里,只有兩個(gè)函數(shù):
掛起
public native void park(boolean isAbsolute, long time);
喚醒
public native void unpark(Thread jthread);?
unpark函數(shù)為線程提供“許可(permit)”,park函數(shù)則等待“許可”。這個(gè)有點(diǎn)像信號(hào)量,但是這個(gè)“許可”是不能疊加的,“許可”是一次性的。
比如線程B連續(xù)調(diào)用了三次unpark函數(shù),當(dāng)線程A調(diào)用park函數(shù)就使用掉這個(gè)“許可”,如果線程A再次調(diào)用park,則進(jìn)入等待狀態(tài)。
注意,unpark函數(shù)可以先于park調(diào)用。比如線程B調(diào)用unpark函數(shù),給線程A發(fā)了一個(gè)“許可”,那么當(dāng)線程A調(diào)用park時(shí),它發(fā)現(xiàn)已經(jīng)有“許可”了,那么它會(huì)馬上再繼續(xù)運(yùn)行。
實(shí)際上,park函數(shù)即使沒有“許可”,有時(shí)也會(huì)無(wú)理由地返回,這點(diǎn)等下再解析。
park/unpark模型真正解耦了線程之間的同步,線程之間不再需要一個(gè)Object或者其它變量來(lái)存儲(chǔ)狀態(tài),不再需要關(guān)心對(duì)方的狀態(tài)。
我們從JDK源碼開始看,java.util.concurrent.locks.LookSupport.park()如下:
1 /**2 * Disables the current thread for thread scheduling purposes unless the3 * permit is available.--->停止當(dāng)前線程的調(diào)度執(zhí)行一直到許可可達(dá)。4 *5 * <p>If the permit is available then it is consumed and the call6 * returns immediately; otherwise the current thread becomes disabled7 * for thread scheduling purposes and lies dormant until one of three8 * things happens:9 *--->當(dāng)許可條件滿足時(shí),當(dāng)前線程會(huì)立即返回。否則會(huì)一直停止線程調(diào)度并且假死一直到下面3件事情發(fā)生: 10 * <ul> 11 * 12 * <li>Some other thread invokes {@link #unpark unpark} with the 13 * current thread as the target; or 14 *--->1.其它線程調(diào)用unpark方法喚醒此線程 15 * <li>Some other thread {@linkplain Thread#interrupt interrupts} 16 * the current thread; or 17 *--->2.其它線程中斷此線程 18 * <li>The call spuriously (that is, for no reason) returns. 19 * </ul> 20 **--->3.此線程未知錯(cuò)誤返回了 21 * <p>This method does <em>not</em> report which of these caused the 22 * method to return. Callers should re-check the conditions which caused 23 * the thread to park in the first place. Callers may also determine, 24 * for example, the interrupt status of the thread upon return.*----》該方法不會(huì)告知是哪個(gè)原因?qū)е碌姆祷亍U{(diào)用方需要重新校驗(yàn)導(dǎo)致線程park的條件。比如中斷狀態(tài)。 25 */ 26 public static void park() { 27 UNSAFE.park(false, 0L);//線程調(diào)用該方法,線程將一直阻塞直到超時(shí)(這里沒有超時(shí)時(shí)間為0),或者是中斷條件出現(xiàn)。 28 }?
這里我們就簡(jiǎn)單看一下park()源碼,目錄:
openjdk-8-src-b132-03_mar_2014\openjdk\hotspot\src\share\vm\runtime\park.cpp
openjdk-8-src-b132-03_mar_2014\openjdk\hotspot\src\share\vm\runtime\park.hpp
openjdk-8-src-b132-03_mar_2014\openjdk\hotspot\src\os\linux\vm\os_linux.cpp
openjdk-8-src-b132-03_mar_2014\openjdk\hotspot\src\os\linux\vm\os_linux.hpp
park.hpp:
1 class Parker : public os::PlatformParker {2 private:3 volatile int _counter ;4 Parker * FreeNext ;5 JavaThread * AssociatedWith ; // Current association6 7 public:8 Parker() : PlatformParker() {9 _counter = 0 ; 10 FreeNext = NULL ; 11 AssociatedWith = NULL ; 12 } 13 protected: 14 ~Parker() { ShouldNotReachHere(); } 15 public: 16 // For simplicity of interface with Java, all forms of park (indefinite, 17 // relative, and absolute) are multiplexed into one call. 18 void park(bool isAbsolute, jlong time); 19 void unpark(); 20 21 // Lifecycle operators 22 static Parker * Allocate (JavaThread * t) ; 23 static void Release (Parker * e) ; 24 private: 25 static Parker * volatile FreeList ; 26 static volatile int ListLock ; 27 28 };os_linux.hpp中,PlatformParker:
1 class PlatformParker : public CHeapObj<mtInternal> {2 protected:3 enum {4 REL_INDEX = 0,5 ABS_INDEX = 16 };7 int _cur_index; // which cond is in use: -1, 0, 18 pthread_mutex_t _mutex [1] ;9 pthread_cond_t _cond [2] ; // one for relative times and one for abs. 10 11 public: // TODO-FIXME: make dtor private 12 ~PlatformParker() { guarantee (0, "invariant") ; } 13 14 public: 15 PlatformParker() { 16 int status; 17 status = pthread_cond_init (&_cond[REL_INDEX], os::Linux::condAttr()); 18 assert_status(status == 0, status, "cond_init rel"); 19 status = pthread_cond_init (&_cond[ABS_INDEX], NULL); 20 assert_status(status == 0, status, "cond_init abs"); 21 status = pthread_mutex_init (_mutex, NULL); 22 assert_status(status == 0, status, "mutex_init"); 23 _cur_index = -1; // mark as unused 初始化時(shí)-1未使用 24 } 25 };可以看到Parker類實(shí)際上用Posix的mutex,condition來(lái)實(shí)現(xiàn)的。
在Parker類里的_counter字段,就是用來(lái)記錄所謂的“許可”的。
park()源碼實(shí)現(xiàn),為了保證源碼的完整性,就直接在源碼上注釋原理了。
1 void Parker::park(bool isAbsolute, jlong time) {2 // Ideally we'd do something useful while spinning, such3 // as calling unpackTime().4 5 // Optional fast-path check:6 // Return immediately if a permit is available.7 // We depend on Atomic::xchg() having full barrier semantics8 // since we are doing a lock-free update to _counter.9 if (Atomic::xchg(0, &_counter) > 0) return;//先嘗試能否直接拿到“許可”,即_counter>0時(shí),如果成功,則把_counter設(shè)置為0,并返回:10 11 Thread* thread = Thread::current();12 assert(thread->is_Java_thread(), "Must be JavaThread");13 JavaThread *jt = (JavaThread *)thread;14 15 // Optional optimization -- avoid state transitions if there's an interrupt pending.16 // Check interrupt before trying to wait17 if (Thread::is_interrupted(thread, false)) {18 return;19 }20 21 // Next, demultiplex/decode time arguments22 timespec absTime;23 if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all24 return;25 }26 if (time > 0) {27 unpackTime(&absTime, isAbsolute, time);28 }29 30 31 // Enter safepoint region32 // Beware of deadlocks such as 6317397.33 // The per-thread Parker:: mutex is a classic leaf-lock.34 // In particular a thread must never block on the Threads_lock while35 // holding the Parker:: mutex. If safepoints are pending both the36 // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.37 ThreadBlockInVM tbivm(jt);//如果不成功,則構(gòu)造一個(gè)ThreadBlockInVM,38 39 // Don't wait if cannot get lock since interference arises from40 // unblocking. Also. check interrupt before trying wait41 if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {42 return;43 }44 45 int status ;46 if (_counter > 0) { // no wait needed然后檢查_counter是不是>0,如果是,則把_counter設(shè)置為0,unlock mutex并返回:47 _counter = 0;48 status = pthread_mutex_unlock(_mutex);49 assert (status == 0, "invariant") ;50 // Paranoia to ensure our locked and lock-free paths interact51 // correctly with each other and Java-level accesses.52 OrderAccess::fence();53 return;54 }55 56 #ifdef ASSERT57 // Don't catch signals while blocked; let the running threads have the signals.58 // (This allows a debugger to break into the running thread.)59 sigset_t oldsigs;60 sigset_t* allowdebug_blocked = os::Linux::allowdebug_blocked_signals();61 pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);62 #endif63 64 OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);65 jt->set_suspend_equivalent();66 // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()67 68 assert(_cur_index == -1, "invariant");69 if (time == 0) {70 _cur_index = REL_INDEX; // arbitrary choice when not timed71 status = pthread_cond_wait (&_cond[_cur_index], _mutex) ;72 } else {73 _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;74 status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;75 if (status != 0 && WorkAroundNPTLTimedWaitHang) {76 pthread_cond_destroy (&_cond[_cur_index]) ;77 pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());78 }79 }80 _cur_index = -1;81 assert_status(status == 0 || status == EINTR ||82 status == ETIME || status == ETIMEDOUT,83 status, "cond_timedwait");84 85 #ifdef ASSERT86 pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);87 #endif88 89 _counter = 0 ;90 status = pthread_mutex_unlock(_mutex) ;91 assert_status(status == 0, status, "invariant") ;92 // Paranoia to ensure our locked and lock-free paths interact93 // correctly with each other and Java-level accesses.94 OrderAccess::fence();95 96 // If externally suspended while waiting, re-suspend97 if (jt->handle_special_suspend_equivalent_condition()) {98 jt->java_suspend_self();99 } 100 }unpark()源碼實(shí)現(xiàn)
1 void Parker::unpark() {2 int s, status ;3 status = pthread_mutex_lock(_mutex);//互斥鎖加鎖4 assert (status == 0, "invariant") ;5 s = _counter;//保存初始counter6 _counter = 1;//置17 if (s < 1) {//如果原本為08 // thread might be parked線程可能被掛起9 if (_cur_index != -1) { 10 // thread is definitely parked 11 if (WorkAroundNPTLTimedWaitHang) { 12 status = pthread_cond_signal (&_cond[_cur_index]);//喚醒在park中等待的線程 13 assert (status == 0, "invariant"); 14 status = pthread_mutex_unlock(_mutex);//釋放鎖 15 assert (status == 0, "invariant"); 16 } else { 17 status = pthread_mutex_unlock(_mutex);//釋放鎖 18 assert (status == 0, "invariant"); 19 status = pthread_cond_signal (&_cond[_cur_index]);//喚醒在park中等待的線程 20 assert (status == 0, "invariant"); 21 } 22 } else { 23 pthread_mutex_unlock(_mutex);//釋放鎖 24 assert (status == 0, "invariant") ; 25 } 26 } else {//如果原本為1,釋放鎖 27 pthread_mutex_unlock(_mutex); 28 assert (status == 0, "invariant") ; 29 } 30 }2.Caches緩存類
Caches-->WeakClassKey-->WeakReference
1 /** cache of subclass security audit results */2 /* Replace with ConcurrentReferenceHashMap when/if it appears in a future3 * release */4 private static class Caches {5 /** cache of subclass security audit results */6 static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =7 new ConcurrentHashMap<>();8 9 /** queue for WeakReferences to audited subclasses */ 10 static final ReferenceQueue<Class<?>> subclassAuditsQueue = 11 new ReferenceQueue<>(); 12 } Caches類中包含了兩個(gè)成員subclassAudits和subclasseAuditsQueue:
subclassAudits——該成員屬性提供了一個(gè)哈希表緩存,該緩存的鍵類型為java.lang.Thread.WeakClassKey,注意看它的值類型是一個(gè)java.lang.Boolean類型的,從其代碼注釋可以知道這個(gè)哈希表緩存中保存的是所有子類的代碼執(zhí)行安全性檢測(cè)結(jié)果;
subclassAuditsQueue——該成員屬性定義了一個(gè)“Queue隊(duì)列”,保存了已經(jīng)審核過的子類弱引用
static class WeakClassKey extends WeakReference<Class<?>>關(guān)于弱引用WeakReference,飛機(jī)票:Java中關(guān)于WeakReference和WeakHashMap的理解
?
?
參考
《JAVA高并發(fā)程序設(shè)計(jì)》電子工業(yè)出版社
Java并發(fā)編程:Thread類的使用
總結(jié)
以上是生活随笔為你收集整理的Thread类源码剖析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring boot实战(第十篇)Sp
- 下一篇: 从Thread.start()方法看Th