java并發(fā)編程之LockSupport

LockSupport,構(gòu)建同步組件的基礎(chǔ)工具,幫AQS完成相應(yīng)線程的阻塞或者喚醒的工作。

LockSupport源碼分析

LockSupport定義了一組以park開頭的方法來阻塞當前線程,unpark來喚醒被阻塞的線程。

阻塞線程

  • park()實現(xiàn)
public static void park() {
    UNSAFE.park(false, 0L);
}

調(diào)用native方法阻塞當前線程。

  • parkNanos(long nanos)實現(xiàn)
public static void parkNanos(long nanos) {
    if (nanos > 0)
        UNSAFE.park(false, nanos);
}

阻塞當前線程,最長不超過nanos納秒,返回條件在park()的基礎(chǔ)上增加了超時返回。

  • parkUntil(long deadline)實現(xiàn)
public static void parkUntil(long deadline) {
    UNSAFE.park(true, deadline);
}

阻塞當前線程,知道deadline時間(deadline - 毫秒數(shù))。

在java6之后在park系列方法新增加了入?yún)?code>Object blocker,用于標識阻塞對象,該對象主要用于問題排查和系統(tǒng)監(jiān)控。

  • park(Object blocker)實現(xiàn)
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}
  • 記錄當前線程等待的對象(阻塞對象);

  • 阻塞當前線程;

  • 當前線程等待對象置為null。

  • parkNanos(Object blocker, long nanos)實現(xiàn)

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);
    }
}

阻塞當前線程,最長等待時間不超過nanos毫秒,同樣,在阻塞當前線程的時候做了記錄當前線程等待的對象操作。

  • parkUntil(Object blocker, long deadline)
public static void parkUntil(Object blocker, long deadline) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(true, deadline);
    setBlocker(t, null);
}

阻塞當前線程直到deadline時間,相同的,也做了阻塞前記錄當前線程等待對象的操作。

到這里,問題來了,為什么在java6要在入?yún)⒁隻locker呢?blocker的作用到底是什么?

先看看線程dump的結(jié)果:


線程dump結(jié)果對比

從線程dump結(jié)果可以看出:
有blocker的可以傳遞給開發(fā)人員更多的現(xiàn)場信息,可以查看到當前線程的阻塞對象,方便定位問題。所以java6新增加帶blocker入?yún)⒌南盗衟ark方法,替代原有的park方法。

喚醒線程

  • unpark(Thread thread)實現(xiàn)
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

喚醒處于阻塞狀態(tài)的線程Thread。

從源碼不難發(fā)現(xiàn),LockSupport所有的方法都是調(diào)用native的park和unpark實現(xiàn)的,接下來我們具體看看HotSpot中的park/unpark的具體實現(xiàn)。

HotSpot里的park/unpark

在HotSpot中,每個java線程都有一個Parker的實例,Parker的定義是這樣子的:


Parker定義

從Parker定義不難看出:

  1. 定義私有屬性_counter:可以理解為是否可以調(diào)用park的一個許可證,只有_count > 0的時候才能調(diào)用;

  2. 提供public方法park和unpark支撐阻塞/喚醒線程;

  3. Parker繼承PlatformParker:


    PlatformParker定義

    從PlatformParker的定義可以看出,Parker實際上是利用Posix的mutex,condition來實現(xiàn)的。

HotSpot park實現(xiàn)

  1. 嘗試是否能可以調(diào)用park,如果_counter > 0,可以調(diào)用,將_counter置為0,返回;


    park步驟1具體實現(xiàn)
  2. 步驟1不成功,構(gòu)造當前線程的ThreadBlockInVM,檢查_counter > 0是否成立,成立則將_counter設(shè)置為0,unlock mutex,返回;


    park步驟2具體實現(xiàn)
  3. 步驟2不成功,根據(jù)等待時間調(diào)用不同的等待函數(shù)等待,如果等待返回正確,將_counter置為0,unlock mutex,返回,park調(diào)用成功。


    park步驟3具體實現(xiàn)

相比之下,unpark的實現(xiàn)就簡單多了。

HotSpot unpark實現(xiàn)

unpark實現(xiàn)

  1. 將_counter置為1;
  2. 判斷之前_counter的值:
  • 小于1時,調(diào)用pthread_cond_signal喚醒在park中等待的線程;
  • 等于1時,unlock mutex,返回。

總結(jié):HotSpot Parker用condition和mutex維護了一個_counter變量,park時,變量_counter置為0,unpark時,變量_counter置為1。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容