? ? 今天來(lái)說(shuō)一說(shuō)LockSupport類,為什么要說(shuō)該類呢?因?yàn)檫@LockSupport類是鎖和同步類的基礎(chǔ),它提供線程的掛起和喚醒。其實(shí)從源碼中也可以看到LockSupport只是多Unsafe類的park系列方法和unpark系列方法進(jìn)行了一層淺淺的封裝。
? ? LockSupport類與每個(gè)使用它的線程都會(huì)關(guān)聯(lián)一個(gè)許可證,在默認(rèn)情況下調(diào)用LockSupport類方法的線程是不持有許可證的。
? ? 下面通過(guò)源碼來(lái)解釋幾個(gè)主要的方法吧。
park()
public static void park() {
UNSAFE.park(false, 0L);
}
????park方法調(diào)用的是Unsafe類的park方法,如果調(diào)用park方法的線程已經(jīng)拿到了與LockSupport關(guān)聯(lián)的許可證,則調(diào)用park方法會(huì)立即返回,否則會(huì)被掛起阻塞。阻塞的線程會(huì)一直阻塞直到下面三個(gè)條件其中之一發(fā)生:
1)當(dāng)其他線程調(diào)用了unpark方法并把當(dāng)前阻塞線程作為參數(shù)傳入,喚醒當(dāng)前阻塞線程。
2)當(dāng)其他線程調(diào)用了阻塞線程的interrupte方法。
3)當(dāng)發(fā)生無(wú)理由的虛假喚醒。
? ? 從上面的源碼可以看到park方法返回并不會(huì)返回任何值,所以調(diào)用該方法者在調(diào)用park方法返回之后需要再對(duì)條件進(jìn)行判斷。
park(Object blocker)
public static void park(Object blocker) {
Thread t = Thread.currentThread();
? ? setBlocker(t, blocker);
? ? UNSAFE.park(false, 0L);
? ? setBlocker(t, null);
}
? ? 和park()方法一樣,調(diào)用的是Unsafe類的park方法,如果調(diào)用park方法的線程已經(jīng)拿到了與LockSupport關(guān)聯(lián)的許可證,則調(diào)用park方法會(huì)立即返回,否則會(huì)被掛起阻塞。不同點(diǎn)在于park(Object blocker)方法傳遞一個(gè)blocker變量,在線程阻塞前會(huì)將blocker變量賦值給當(dāng)前線程的本地變量parkBlocker,UNSAFE.park返回之后,再重新將當(dāng)前線程的本地變量parkBlocker設(shè)置為null。
? ? 設(shè)置blocker變量有什么用呢?可以通過(guò)getBlocker(Thread t)方法獲得是哪個(gè)對(duì)象調(diào)用了park方法阻塞了當(dāng)前線程,可以幫助對(duì)堆棧進(jìn)行分析。
? ? 關(guān)于LockSupport中帶時(shí)間的park方法就在這一句帶過(guò)了,parkNanos(long nanos)阻塞nanos秒后返回,相對(duì)時(shí)間,parkUntil(long deadline)阻塞直到deadline時(shí)間為止,絕對(duì)時(shí)間。
unpark(Thread thread)
public static void unpark(Thread thread) {
if (thread !=null)
UNSAFE.unpark(thread);
}
? ? 為指定的線程獲得許可證,在獲得許可證之前如果當(dāng)前線程阻塞,則獲得許可證之后會(huì)被喚醒返回。如果參數(shù)中的線程已經(jīng)獲得過(guò)許可證了,則不會(huì)再次獲得。
? ? 下面看兩個(gè)例子:
例一:
LockSupport.unpark(Thread.currentThread());
LockSupport.park(Thread.currentThread());
? ? 當(dāng)前線程會(huì)在調(diào)用park方法立馬返回,因?yàn)楫?dāng)前線程在調(diào)用park之前調(diào)用了unpark返回獲得了許可證。
例二:
LockSupport.unpark(Thread.currentThread());
LockSupport.unpark(Thread.currentThread());
LockSupport.park(Thread.currentThread());
LockSupport.park(Thread.currentThread());
? ? 當(dāng)前線程會(huì)被阻塞在第二個(gè)park方法,雖然在調(diào)用park方法之前調(diào)用了兩次unpark,但是許可證不能疊加,所以當(dāng)前線程只獲得了一個(gè)許可證,而在第一次調(diào)用park方法的時(shí)候已經(jīng)消耗掉該許可證,所以在第二次調(diào)用park方法已沒(méi)有許可證,則會(huì)被掛起阻塞。
? ? LockSupport類是之后講解鎖和其他同步類的底層實(shí)現(xiàn),所以理解LockSupport類對(duì)之后的理解鎖以及同步類是有幫助的。? ?
? ? 今天的分享就到這,有看不明白的地方一定是我寫的不夠清楚,所有歡迎提任何問(wèn)題以及改善方法。