park和unpark


1 介紹

LockSupport類是Java6(JSR166-JUC)引入的一個類,提供了基本的線程同步原語。LockSupport提供的兩個主要方法就是park和unpark。

park譯為“停車”,官方文檔意為:許可。為了方便理解,在這里我們可以理解為阻塞,等待,掛起,而unpark我們理解為喚醒,恢復。

LockSupport同步線程和wait/notify不一樣,LockSupport並不需要獲取對象的監視器,而是給線程一個“許可”(permit)。而permit只能是0個或者1個。unpark會給線程一個permit,而且最多是1;而park會消耗一個permit並返回,如果線程沒有permit則會阻塞。

2 特點以及與wait/notify區別

park和unpark有以下特點

  • permit不能疊加,也就是說permit的個數要么是0,要么是1。也就是不管連續調用多少次unpark,permit也是1個。線程調用一次park就會消耗掉permit,再一次調用park又會阻塞住。舉例如下
public class App {
    public static void main(String[] args) throws Exception {

        Thread boyThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("boy: 我要吃雞");
                LockSupport.park(); 
                System.out.println("boy: park1");
                LockSupport.park(); // 第二次會阻塞住,因為只有一個permit
                System.out.println("boy: park2");
                System.out.println("boy: 開始吃雞了");
            }
        });

        Thread girlThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(4000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("girl: 允許");
                LockSupport.unpark(boyThread); // unpark兩次,但是permit不會疊加
                LockSupport.unpark(boyThread);
            }
        });

        boyThread.start();
        girlThread.start();
    }

運行結果是

boy: 我要吃雞
girl: 允許
boy: park1
  • unpark可以先於park調用。也就是我們在使用park和unpark的時候可以不用擔心park的時序問題造成死鎖。相比之下,wait/notify存在時序問題,wait必須在notify調用之前調用,否則雖然另一個線程調用了notify,但是由於在wait之前調用了,wait感知不到,就造成wait永遠在阻塞。我們可以考慮下之前的一個例子 為什么WAIT必須在同步塊中, 該例子中沒有使用同步塊產生死鎖的原因是由於錯誤的條件判斷,導致wait調用在notify之后,所以引起線程一直掛起。而unpark和park語義更加明確,它可以指明就是讓某一個線程阻塞/接觸阻塞。

  • park和unpark調用的時候不需要獲取同步鎖。我想原因應該也是和上述類似,我們可以先分析下wait/notify需要同步鎖的原因是因為兩個線程存在競態關系,必須保證在正確的條件下調用wait/notify,如果判斷錯誤了由於調用時序問題就會造成阻塞。而park/unpark不存在時序問題,所以線程可以繼續運行。

  • park的一般用法。park方法也有可能在沒有"任何理由"的情況下返回,所以通常要在一個循環中使用它並重新判斷可以返回的條件。這一點和Object.wait方法一樣,使用模式如下:

while (!canProceed()) { ... LockSupport.park(this); }}

當然如果沒有任何條件就park的話,也不需要while了

3 參考

  1. http://www.ituring.com.cn/article/497544
  2. https://blog.csdn.net/xiaoliuliu2050/article/details/73998455
  3. https://blog.csdn.net/hengyunabc/article/details/28126139
  4. https://juejin.im/entry/5a13ca8251882531e9446eaa


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM