AQS阻塞喚醒工具LockSupport


LockSupport在JDK源碼中描述爲:構建鎖和其餘同步類的基本線程阻塞原語,構建更高級別的同步工具集。LockSupport提供的park/unpark從線程的粒度上進行阻塞和喚醒,park/unpark模型真正解耦了線程之間的同步,線程之間再也不須要一個Object或者其它變量來存儲狀態。
html

本文從阻塞喚醒的語義入手,解釋LockSupport的內在機制和注意點,最後與Object的wait和notify作對比,包括如下內容:java

  • 阻塞和喚醒的語義
  • 許可機制
  • 底層實現
  • 用法
  • 與Object的wait和notify區別

阻塞的語義

阻塞是線程在知足某種條件以前暫時中止運行,而被動釋放出CPU資源。進入該狀態的線程不會主動進入線程隊列等待CPU資源,而須要等待知足條件後被喚醒,才能讓該線程從新進入到線程隊列中排隊等待CPU資源。通常形成線程阻塞的緣由有:等待獲取一個已經被其餘線程持有的排他鎖、等待某一操做結束、等待某一個時間段。線程阻塞後會被掛起,此時會處於BLOCKEDWAITINGTIMED_WAITING。線程阻塞後會讓出CPU資源,這是爲避免在自旋上浪費過多的CPU資源,是忙等待(busy wait)的一種優化。微信

許可機制

LockSupport經過「許可」(permit)機制,使用park/unpark實現線程的阻塞和喚醒。許但是指容許線程繼續執行,是線程執行的開關,當開關關閉時,線程會阻塞,當開關打開時,線程會當即執行。多線程

park意指線程在獲取許可以前會暫停執行(阻塞在獲取許可)。這裏的「許可」與線程相關聯,相似二元信號量,不可疊加且一個線程只能有一個。有些文章描述「許可」是一次性的,例如當線程A調用park消耗掉一個「許可」(最多隻有一個「許可」),在未調用unpark釋放出線程A的該「許可」以前,線程A再次調用park時會阻塞在獲取「許可」。下文引自Understanding JVM Thread States併發

there can be only one permit per thread, when thread consumes the permit, it disappears.app

出於線程調度的目的,調用park時會阻塞直到許可可用時。若是許可可用,調用park就會當即返回。當前線程就會阻塞,直到調用 unpark 方法,釋放出許可。因爲許但是默認被佔用的,當前線程在啓動後調用 park 的話就獲取不到許可,所以就進入阻塞狀態。框架

底層實現

LockSupport是使用Unsafe的park實現的,HotSpot Parker用condition和mutex維護了一個_counter變量,park時,變量_counter置爲0,unpark時,變量_counter置爲1。park操做檢查該值是否爲1,爲1直接返回;不爲1,則阻塞。jvm

用法

看到一個關於park/unpark通俗易懂的的例子,代碼以下:ide

 1 public static void main(String[] args) throws InterruptedException {
 2   Thread threadA = new Thread(new Runnable() {
 3     @Override
 4     public void run() {
 5       System.out.println("週末了我在打遊戲");
 6       LockSupport.park();
 7       System.out.println("陪女友逛逛街");
 8     }
 9   });
10   threadA.start();
11   Thread.sleep(3000);
12   System.out.println("女友準備要喊男友逛街");
13   LockSupport.unpark(threadA);
14 }

在第6行park執行操做時,線程嘗試獲取許可,因爲線程threadA在啓動後默認已經獲取了許可,park必須等待許可釋放後才能夠執行。當主線程調用unpark方法釋放threadA的許可,threadA才能夠繼續執行第7行。 工具

與wait和notify區別

park/unpark與wati/notify都提供阻塞喚醒的功能,用作線程間同步,不過二者 的粒度不一樣,park/unpark做用在線程上,而wait/notify做用在對象上,兩者沒有交集。Object的wait/notify使用前必須獲取對象的監視器,而park/unpark不須要。

寫做不易,痛並快樂着;理解可能存在誤差,句句斟酌推敲;抵制抄襲,踐行原創技術之路。若是本文能對您有所幫助,實爲榮幸,我是葛一凡。

原文
微信公衆號微信公衆號

參考

    1. Java的LockSupport.park()實現分析
    2. java線程阻塞中斷和LockSupport的常見問題
    3. 多線程之Java線程阻塞與喚醒
    4. Understanding JVM Thread States
    5. java併發包系列—LockSupport
    6. Java併發包源碼學習之AQS框架(三)LockSupport和interrupt
相關文章
相關標籤/搜索