學(xué)院網(wǎng)站建設(shè)與管理辦法今日國家新聞
前言:本文將介紹LockSupport類中的方法和部分源碼,以及面試常問到的一個(gè)小問題,感興趣的大佬可以指點(diǎn)下。
希望能夠加深自己的印象以及幫助到其他的小伙伴兒們😉😉。
如果文章有什么需要改進(jìn)的地方還請(qǐng)大佬不吝賜教👏👏。
小威在此先感謝各位大佬啦~~🤞🤞
🏠個(gè)人主頁:小威要向諸佬學(xué)習(xí)呀
🧑個(gè)人簡介:大家好,我是小威,一個(gè)想要與大家共同進(jìn)步的男人😉😉
目前狀況🎉:24屆畢業(yè)生,曾經(jīng)在某央企公司實(shí)習(xí),目前在某稅務(wù)公司實(shí)習(xí)👏👏💕歡迎大家:這里是CSDN,我總結(jié)知識(shí)的地方,歡迎來到我的博客,我親愛的大佬😘
以下正文開始
LockSupport類常用方法源碼
LockSupport只是一個(gè)簡單的基礎(chǔ)類,位于java.util.concurrent.locks包下,多用于線程的阻塞和喚醒,因此LockSupport也被稱為其他線程的工具類。
LockSupport類的源碼有標(biāo)注,LockSupport類無法實(shí)例化。LockSupport類的底層是有Unsafe類實(shí)現(xiàn)的,LockSupport加載時(shí)的初始化也用到了Unsafe獲取成員的偏移量,其源碼如下:
// Hotspot implementation via intrinsics APIprivate static final sun.misc.Unsafe UNSAFE;private static final long parkBlockerOffset;private static final long SEED;private static final long PROBE;private static final long SECONDARY;static {try {UNSAFE = sun.misc.Unsafe.getUnsafe();Class<?> tk = Thread.class;parkBlockerOffset = UNSAFE.objectFieldOffset(tk.getDeclaredField("parkBlocker"));SEED = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSeed"));PROBE = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomProbe"));SECONDARY = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSecondarySeed"));} catch (Exception ex) { throw new Error(ex); }}
LockSupport類中有一些核心的線程操作方法,多用于線程的阻塞與喚醒。
調(diào)用park()方法使線程阻塞:
public static void park(Object blocker) {Thread t = Thread.currentThread();setBlocker(t, blocker);UNSAFE.park(false, 0L);setBlocker(t, null);}private static void setBlocker(Thread t, Object arg) {// Even though volatile, hotspot doesn't need a write barrier here.UNSAFE.putObject(t, parkBlockerOffset, arg);}
調(diào)用park(Object blocker)對(duì)傳入的線程進(jìn)行阻塞
public static void park(Object blocker) {Thread t = Thread.currentThread();setBlocker(t, blocker);UNSAFE.park(false, 0L);setBlocker(t, null);}
在截止時(shí)間之前阻塞傳入的某個(gè)線程:
public static void parkUntil(Object blocker, long deadline) {Thread t = Thread.currentThread();setBlocker(t, blocker);UNSAFE.park(true, deadline);setBlocker(t, null);}
在nanos的時(shí)間范圍內(nèi)阻塞傳入的線程:
public static void parkNanos(Object blocker, long nanos) {if (nanos > 0) {Thread t = Thread.currentThread();setBlocker(t, blocker);UNSAFE.park(false, nanos);setBlocker(t, null);}}
喚醒傳入的線程:
public static void unpark(Thread thread) {if (thread != null)UNSAFE.unpark(thread);}
wait/notify方法和park/unpark方法區(qū)別
LockSupport類中的方法還有很多,在此先列舉到這里。當(dāng)我們看到阻塞和喚醒方法時(shí),我們會(huì)聯(lián)想到另一組喚醒方法wait()和notify(),這兩組方法還是有所區(qū)別的。
這里直接記錄下結(jié)論:wait和notify方法只能在同步代碼塊中使用(即必須與synchronized連用);必須先執(zhí)行wait方法,然后再執(zhí)行notify方法喚醒線程,調(diào)換順序的話線程仍處于阻塞狀態(tài)。
而park()和unpark()方法與之不同,這里可以通過代碼運(yùn)行結(jié)果來看:
package XIAOWEI;
import java.util.concurrent.locks.LockSupport;public class Xiaowei{public static void main(String[] args) {Thread A = new Thread(()-> {System.out.println("線程A已經(jīng)被阻塞QWQ");LockSupport.park();System.out.println("線程A被線程B喚醒啦~~~");});A.start();new Thread(()->{System.out.println("線程B在喚醒線程A ing~~~");LockSupport.unpark(A);},"B").start();}
}
那如果我們先通過線程B喚醒線程A,然后再讓線程A阻塞呢(讓線程A的阻塞休眠兩秒)?
package XIAOWEI;
import java.util.concurrent.locks.LockSupport;
public class Xiaowei {public static void main(String[] args) {Thread A = new Thread(()-> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("線程A已經(jīng)被阻塞QWQ(第二版)");LockSupport.park();System.out.println("線程A被線程B喚醒啦~~~(第二版)");});A.start();new Thread(()->{System.out.println("線程B在喚醒線程A ing~~~駕駕駕");LockSupport.unpark(A);},"B").start();}
}
由上面輸出結(jié)果來看,雖然線程B先喚醒了線程A,然后線程A再開始阻塞,但是線程A還是處于喚醒狀態(tài),這是為什么呢?
接下來我找了段LockSupport類中的注釋,其實(shí)有時(shí)看看注釋也挺有意思的哈哈:
* <p>This class associates, with each thread that uses it, a permit* (in the sense of the {@link java.util.concurrent.Semaphore* Semaphore} class). A call to {@code park} will return immediately* if the permit is available, consuming it in the process; otherwise* it <em>may</em> block. A call to {@code unpark} makes the permit* available, if it was not already available. (Unlike with Semaphores* though, permits do not accumulate. There is at most one.)
這段話大意是說,LockSupport類使用permits這個(gè)東西來實(shí)現(xiàn)線程的阻塞和喚醒。每一個(gè)線程都會(huì)使用到(擁有)permit,且permit的值默認(rèn)為0。接著它又說,這個(gè)概念和Semaphore信號(hào)量差不多,但是permit的值只有0和1兩個(gè)值。哦~原來是這樣。
對(duì)于上面例子,線程B調(diào)用unpark方法喚醒A后,會(huì)使得線程A的permit值為1,當(dāng)線程調(diào)用park方法使自己阻塞時(shí),發(fā)現(xiàn)自己已經(jīng)有許可(permit)了,就會(huì)繼續(xù)向下執(zhí)行業(yè)務(wù),而不會(huì)阻塞不動(dòng)。
好了,本篇文章就先分享到這里了,后續(xù)會(huì)繼續(xù)分享其他方面的知識(shí),感謝大佬認(rèn)真讀完支持咯~
文章到這里就結(jié)束了,如果有什么疑問的地方請(qǐng)指出,諸佬們一起討論😁
希望能和諸佬們一起努力,今后我們頂峰相見🍻
再次感謝各位小伙伴兒們的支持🤞