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

溫馨提示×

溫馨提示×

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

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

線程阻塞喚醒工具LockSupport怎么使用

發布時間:2023-01-28 15:38:02 來源:億速云 閱讀:147 作者:iii 欄目:開發技術

本篇內容主要講解“線程阻塞喚醒工具LockSupport怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“線程阻塞喚醒工具LockSupport怎么使用”吧!

    LockSupport 簡介

    LockSupport 是 Java 并發編程中一個非常重要的組件,我們熟知的并發組件 Lock、線程池、CountDownLatch 等都是基于 AQS 實現的,而 AQS 內部控制線程阻塞和喚醒又是通過 LockSupport 來實現的。

    從該類的注釋上也可以發現,它是一個控制線程阻塞和喚醒的工具,與以往的不同是它解決了曾經 wait()、notify()、await()、signal() 的局限。

    回顧 synchronized 和 Lock

    我們知道 Java 中實現并發安全通常會通過這兩種加鎖的方式,對于 synchronized 加鎖的方式,如果我們想要控制線程的阻塞和喚醒是通過鎖對象的 wait()notify() 方法,以下面循環交替打印 AB 為例

    int status = 2;
    public static void main(String[] args) throws InterruptedException {
        TestSync obj = new TestSync();
         new Thread(() -> {
            synchronized (obj){
                while (true){
                    if(obj.status == 1){
                        obj.wait();
                    }
                    System.out.println("A");
                    obj.status = 1;
                    TimeUnit.SECONDS.sleep(1);
                    obj.notify();
                }
            }
         }).start();
        new Thread(() -> {
           synchronized (obj){
              while (true){
                  if(obj.status == 2){
                      obj.wait();
                  }
                  System.out.println("B");
                  obj.status = 2;
                  TimeUnit.SECONDS.sleep(1);
                  obj.notify();
              }
           }
        }).start();
    }

    如果我們使用 Lock 實現類,上述代碼幾乎是一樣的,只是先獲取 Condition 對象

     Condition condition = lock.newCondition();

    obj.wait() 換成 condition.await()obj.notify() 換成 condition.signal() 即可。

    LockSupport 和 synchronized 和 Lock 的阻塞方式對比

    技術阻塞喚醒方式局限
    synchronized使用鎖對象的 wait()、notify()1. 只能用在 synchronized 包裹的同步代碼塊中 2. 必須先 wait() 才能 notify()
    Lock使用 condition 的 await()、signal()1. 只能用在 lock 鎖住的代碼塊中 2. 必須先 await() 才能 signal()
    LockSupportpark()、unpark(Thread t)沒有限制

    LockSupport 的使用

    下面代碼中,我們使用 LockSupport 去阻塞和喚醒線程,我們可以多次嘗試,LockSupportpark()unpark() 方法沒有先后順序的限制,也不需要捕獲異常,也沒有限制要在什么代碼塊中才能使用。

        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(() -> {
                System.out.println("A");
                LockSupport.park();
                System.out.println("被喚醒");
            });
            t1.start();
            TimeUnit.SECONDS.sleep(2);
            new Thread(() -> {
                System.out.println("B");
                LockSupport.unpark(t1);
            }).start();
        }

    LockSupport 注意事項

    許可證提前發放

    從該類的注釋中我們可以看到這個類存儲了使用它的線程的一個許可證,當調用 park() 方法的時候會判斷當前線程的許可證是否存在,如果存在將直接放行,否則就阻塞。

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("A");
            LockSupport.park();//不會阻塞
            System.out.println("被喚醒");
        });
        t1.start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            System.out.println("B");
            System.out.println("先調用 unpark()");
            LockSupport.unpark(t1);
        },"t2").start();
    }

    看這個代碼示例,這里我們在 t2 中先讓線程 t1 unpark(), 然后在 t1 中調用 park(), 結果并不會阻塞 t1 線程。因為在 t2 中調用 LockSupport.unpark(t1); 的時候相當于給 t1 提前準備好了許可證。

    許可證不會累計

    LockSupport.unpark(t1); 無論調用多少次,t1 的通行證只有一個,當在 t1 中調用兩次 park() 方法時線程依然會被阻塞。

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("A");
            LockSupport.park();
            LockSupport.park();
            System.out.println("被喚醒");
        });
        t1.start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            System.out.println("B");
            System.out.println("先調用 unpark()");
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);
        },"t2").start();
    }

    以上述代碼為例,t1 將被阻塞。

    LockSupport 底層實現

    觀察源碼發現 park() 和 unpark() 最底下調用的是 native() 方法,源碼在 C++ 中實現

    @IntrinsicCandidate
    public native void park(boolean isAbsolute, long time);
    @IntrinsicCandidate
    public native void unpark(Object thread);

    到此,相信大家對“線程阻塞喚醒工具LockSupport怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

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

    AI

    津南区| 德钦县| 丰镇市| 英吉沙县| 孝义市| 安乡县| 体育| 福泉市| 营山县| 鹤壁市| 宜黄县| 遵化市| 略阳县| 余干县| 凉城县| 富民县| 常山县| 黄陵县| 嘉荫县| 湖南省| 杭锦后旗| 柳州市| 饶河县| 罗江县| 静安区| 祁阳县| 乌兰县| 朝阳区| 鸡西市| 河津市| 阿拉善盟| 清苑县| 昔阳县| 鄂托克前旗| 苏尼特左旗| 东山县| 巴林右旗| 肃南| 永康市| 怀仁县| 潼关县|