中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

LockSupport的原理和作用是什么

發布時間:2021-06-28 16:21:22 來源:億速云 閱讀:146 作者:chen 欄目:大數據

本篇內容介紹了“LockSupport的原理和作用是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

LockSupport是什么

用于創建鎖和其他同步類的基本線程阻塞原語。
使用它,可以用來構建一些特定邏輯的鎖。jdk并發包的AQS框架就依賴了它。

LockSupport有什么作用

它提供了線程的阻塞和喚醒。
每當一個線程使用它,那么就可以當作這個線程維持了一個二元信號量,可以比作持有許可證。
調用pack()方法,如果有許可證,那么消耗它并且直接返回,線程繼續執行下去。反之,則阻塞。
調用unpack()方法,如果許可證不可用,那么就變成可用,如果是可用,那么就不做其他操作。也就是說,許可證不可以多次累加。
因為有許可證這種中間介質,也就避免了調用線程不推薦的Thread.suspend()Thread.resume()而導致的線程失活的竟態情況。這里我個人的理解是,線程調度的復雜性和延遲。比如說:線程的休眠和暫停并不能夠做到即可馬上、命令之間的重排等等。并且,park()也額外支持了線程打斷和超時功能。
類的文檔里面額外提及了一個慣用法,說的是pack()調用會"無理由"返回,從而導致線程莫名的執行下去。那么慣用法就是把pack()邏輯包裝在一個循環當中,并且循環退出的條件就是線程等待同步許可的條件。這就相當于一個自旋的優化,只是需要unpack()配合。

一個阻塞線程的簡單范例:

public static void main(String[] args) {
    LockSupport.park();
    System.out.println("主線程阻塞,并不會打印當前消息");
}

一個通用的使用范式:

    public static void main(String[] args) throws InterruptedException {
        Thread busThreadJim = new Thread(() -> {

            System.out.println("參數檢查...");
            System.out.println("執行業務邏輯...");
            System.out.println("進入狀態同步點");
            LockSupport.park("因為可能原因A而阻塞住線程");

            System.out.println("同步點完成,進步業務收尾階段...");
            System.out.println("進入最后一個同步點結束");
            LockSupport.park("報告這個線程當前的工作程度或者狀態xxxx");

            System.out.println("業務邏輯完成退出");
        });
        busThreadJim.start();

        System.out.println("控制線程或者監控線程開始做其他邏輯...");
        Thread.sleep(2000);
        System.out.println("檢查工作線程是否阻塞住,為什么:" + LockSupport.getBlocker(busThreadJim));
        LockSupport.unpark(busThreadJim);

        // 如果線程調度慢 LockSupport.getBlocker獲取到null
        // 也就是說工作線程還沒有阻塞住
        System.out.println("可以通過阻塞對象來傳出一些線程工作信息:" + LockSupport.getBlocker(busThreadJim));
        System.out.println("當然共享變量也是可以的");
        LockSupport.unpark(busThreadJim);

        System.out.println("邏輯完成");
    }

多次unpack()也只能消耗一次

    public static void main(String[] args) throws InterruptedException {

        Thread worker = new Thread(() -> {

            System.out.println("執行業務邏輯...");
            System.out.println("進入狀態同步點...");

            LockSupport.park();

            System.out.println("同步點完成,進步業務收尾階段...");

            LockSupport.park();

            System.out.println("最后一個同步點結束");
        });

        worker.start();
        LockSupport.unpark(worker);
        LockSupport.unpark(worker);

        Thread.sleep(2000);

        LockSupport.unpark(worker);
    }

設計代碼邏輯的時候,盡量有明確的阻塞條件,然后選擇帶有時間截至的函數和提供阻塞信息的對象。
理論上來說,應該用不到這個類。但是一旦用到了,估計就是設計很基礎的東西,上面肯定有復雜的邏輯。沒有阻塞信息到時候邏輯排查是要命的。

與wait/notify機制的區別

  1. wait/notify必須在同步代碼塊中使用,光這一點就感覺到限制比較大。

  2. wait/notify操作的是對象,然后才能映射到對象所在的線程,思考方式有點饒。

  3. 復雜的邏輯,特別是嵌套,特別窒息。

源碼實現關鍵點

public class LockSupport {
    private LockSupport() {} // 該類無法實例化

    // 所有的功能都代理給內部來實現
    private static final sun.misc.Unsafe UNSAFE;
    
    // 把當前線程阻塞住
    public static void park() {
        UNSAFE.park(false, 0L);
    }

    // 把當前執行線程與一個阻塞對象相關連
    // 這樣子關注對象就變成線程而非對象
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }
    
    // 下面就是一系列時間相關函數
    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 parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(true, deadline);
        setBlocker(t, null);
    }

    public static void parkNanos(long nanos) {
        if (nanos > 0)
            UNSAFE.park(false, nanos);
    }

    public static void parkUntil(long deadline) {
        UNSAFE.park(true, deadline);
    }

    // 喚醒目標也是線程 跟阻塞關注點相同
    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }

    // 返回阻塞對象信息
    // 如果頻繁的pack,那么該對象可能一直在變更,它的生命周期會比較短,只是最近一次阻塞的信息
    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
    }
}

值得注意的關注點在于blocker的信息獲取,直接操作內存,因為線程已經阻塞住,只能通過這種機制來獲取阻塞線程內信息。

“LockSupport的原理和作用是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

噶尔县| 富源县| 河间市| 渝中区| 南充市| 甘泉县| 格尔木市| 全州县| 宁强县| 武定县| 札达县| 南召县| 宿松县| 泽普县| 玉林市| 故城县| 田东县| 桑日县| 黑龙江省| 区。| 甘南县| 桂平市| 宜君县| 西华县| 绵阳市| 嘉黎县| 肥乡县| 玉山县| 万源市| 石渠县| 镇康县| 彭州市| 修文县| 政和县| 阜宁县| 扎兰屯市| 霍林郭勒市| 尉氏县| 新闻| 资源县| 青铜峡市|