亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

線程阻塞喚醒工具 LockSupport使用詳解

 更新時(shí)間:2023年01月26日 13:10:35   作者:暮色妖嬈丶  
這篇文章主要為大家介紹了線程阻塞喚醒工具LockSupport使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

LockSupport 簡(jiǎn)介

LockSupport 是 Java 并發(fā)編程中一個(gè)非常重要的組件,我們熟知的并發(fā)組件 Lock、線程池、CountDownLatch 等都是基于 AQS 實(shí)現(xiàn)的,而 AQS 內(nèi)部控制線程阻塞和喚醒又是通過(guò) LockSupport 來(lái)實(shí)現(xiàn)的。

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

回顧 synchronized 和 Lock

我們知道 Java 中實(shí)現(xiàn)并發(fā)安全通常會(huì)通過(guò)這兩種加鎖的方式,對(duì)于 synchronized 加鎖的方式,如果我們想要控制線程的阻塞和喚醒是通過(guò)鎖對(duì)象的 wait()notify() 方法,以下面循環(huán)交替打印 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 實(shí)現(xiàn)類,上述代碼幾乎是一樣的,只是先獲取 Condition 對(duì)象

 Condition condition = lock.newCondition();

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

LockSupport 和 synchronized 和 Lock 的阻塞方式對(duì)比

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

LockSupport 的使用

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

    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 注意事項(xiàng)

許可證提前發(fā)放

從該類的注釋中我們可以看到這個(gè)類存儲(chǔ)了使用它的線程的一個(gè)許可證,當(dāng)調(diào)用 park() 方法的時(shí)候會(huì)判斷當(dāng)前線程的許可證是否存在,如果存在將直接放行,否則就阻塞。

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();//不會(huì)阻塞
        System.out.println("被喚醒");
    });
    t1.start();
    TimeUnit.SECONDS.sleep(2);
    new Thread(() -> {
        System.out.println("B");
        System.out.println("先調(diào)用 unpark()");
        LockSupport.unpark(t1);
    },"t2").start();
}

看這個(gè)代碼示例,這里我們?cè)?t2 中先讓線程 t1 unpark(), 然后在 t1 中調(diào)用 park(), 結(jié)果并不會(huì)阻塞 t1 線程。因?yàn)樵?t2 中調(diào)用 LockSupport.unpark(t1); 的時(shí)候相當(dāng)于給 t1 提前準(zhǔn)備好了許可證。

許可證不會(huì)累計(jì)

LockSupport.unpark(t1); 無(wú)論調(diào)用多少次,t1 的通行證只有一個(gè),當(dāng)在 t1 中調(diào)用兩次 park() 方法時(shí)線程依然會(huì)被阻塞。

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("先調(diào)用 unpark()");
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
    },"t2").start();
}

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

LockSupport 底層實(shí)現(xiàn)

觀察源碼發(fā)現(xiàn) park() 和 unpark() 最底下調(diào)用的是 native() 方法,源碼在 C++ 中實(shí)現(xiàn)

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

對(duì),這只是個(gè)標(biāo)題,卷不動(dòng)了,不去看 C/C++ 了。。。。

結(jié)語(yǔ)

LockSupport 是 Java 并發(fā)編程中非常重要的組件,這是我們下一步閱讀 AQS(AbstractQueuedSynchronizer) 源碼的基礎(chǔ)??傊覀冎灰涀∷强刂凭€程阻塞和喚醒的工具,并且知道它與其他阻塞喚醒方式的區(qū)別即可。

以上就是線程阻塞喚醒工具 LockSupport使用詳解的詳細(xì)內(nèi)容,更多關(guān)于喚醒 LockSupport線程阻塞的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論