欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?LockSupport常用方法的源碼分析

 更新時(shí)間:2023年02月20日 14:04:37   作者:小威要向諸佬學(xué)習(xí)呀  
這篇文章主要為大家詳細(xì)介紹了Java?LockSupport類(lèi)中的方法和部分源碼,以及面試常問(wèn)到的一個(gè)小問(wèn)題,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

LockSupport類(lèi)常用方法源碼

LockSupport只是一個(gè)簡(jiǎn)單的基礎(chǔ)類(lèi),位于java.util.concurrent.locks包下,多用于線程的阻塞和喚醒,因此LockSupport也被稱(chēng)為其他線程的工具類(lèi)。

LockSupport類(lèi)的源碼有標(biāo)注,LockSupport類(lèi)無(wú)法實(shí)例化。LockSupport類(lèi)的底層是有Unsafe類(lèi)實(shí)現(xiàn)的,LockSupport加載時(shí)的初始化也用到了Unsafe獲取成員的偏移量,其源碼如下:

    // Hotspot implementation via intrinsics API
    private 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類(lèi)中有一些核心的線程操作方法,多用于線程的阻塞與喚醒。

調(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類(lèi)中的方法還有很多,在此先列舉到這里。當(dāng)我們看到阻塞和喚醒方法時(shí),我們會(huì)聯(lián)想到另一組喚醒方法wait()和notify(),這兩組方法還是有所區(qū)別的。

這里直接記錄下結(jié)論:wait和notify方法只能在同步代碼塊中使用(即必須與synchronized連用);必須先執(zhí)行wait方法,然后再執(zhí)行notify方法喚醒線程,調(diào)換順序的話線程仍處于阻塞狀態(tài)。

而park()和unpark()方法與之不同,這里可以通過(guò)代碼運(yùn)行結(jié)果來(lái)看:

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();
    }
}

那如果我們先通過(guò)線程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é)果來(lái)看,雖然線程B先喚醒了線程A,然后線程A再開(kāi)始阻塞,但是線程A還是處于喚醒狀態(tài),這是為什么呢?

接下來(lái)我找了段LockSupport類(lèi)中的注釋?zhuān)鋵?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.)

這段話大意是說(shuō),LockSupport類(lèi)使用permits這個(gè)東西來(lái)實(shí)現(xiàn)線程的阻塞和喚醒。每一個(gè)線程都會(huì)使用到(擁有)permit,且permit的值默認(rèn)為0。接著它又說(shuō),這個(gè)概念和Semaphore信號(hào)量差不多,但是permit的值只有0和1兩個(gè)值。哦~原來(lái)是這樣。

對(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)。

到此這篇關(guān)于Java LockSupport常用方法的源碼分析的文章就介紹到這了,更多相關(guān)Java LockSupport內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論