Java併發編程之LookSupport

個人博客請訪問 http://www.x0100.top              

java.util.concurrent 中源碼頻繁使用的 LockSupport 來阻塞線程和喚醒線程,如 AQS 的底層實現用到 LockSupport.park()方法和 LockSupport.unpark()方法。

LockSupport 到底是什麼?同樣是阻塞和喚醒線程爲什麼不用 Object 的 wait()/notify 方法?

1. LockSupprot 方法介紹

LockSupport 提供 park()和 unpark()方法實現阻塞線程和解除線程阻塞。

阻塞線程:

  • void park():阻塞當前線程,如果調用 unpark 方法或者當前線程被中斷,才能從 park()方法中返回

  • void park(Object blocker):功能同方法 1,入參增加一個 Object 對象,用來記錄導致線程阻塞的阻塞對象,方便進行問題排查;

  • void parkNanos(long nanos):阻塞當前線程,最長不超過 nanos 納秒,增加了超時返回的特性;

  • void parkNanos(Object blocker, long nanos):功能同方法 3,入參增加一個 Object 對象,用來記錄導致線程阻塞的阻塞對象,方便進行問題排查;

  • void parkUntil(long deadline):阻塞當前線程,直到 deadline;

  • void parkUntil(Object blocker, long deadline):功能同方法 5,入參增加一個 Object 對象,用來記錄導致線程阻塞的阻塞對象,方便進行問題排查;

每個 park 方法都對應有一個帶有 Object 阻塞對象的重載方法。增加了一個 Object 對象作爲參數,此對象在線程受阻塞時被記錄,以允許監視工具和診斷工具確定線程受阻塞的原因。

喚醒線程:

void unpark(Thread thread):喚醒處於阻塞狀態的指定線程

使用舉例

public class LockSupportDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            LockSupport.park();
            System.out.println("thread線程被喚醒");
        });
        thread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LockSupport.unpark(thread);
    }
}
thread線程park阻塞。
主線程sleep3s之後,unpark(thread)。
thread被喚醒,輸出"thread線程被喚醒"。

2. 原理

每個線程都會與一個許可關聯,這個許可對應一個 Parker 的實例,Parker 有一個 int 類型的屬性_count。

park()方法:

  1. 將_count 變爲 0

  2. 如果原_count==0,將線程阻塞

unpark()方法:

  1. 將_count 變爲 1

  2. 如果原_count==0,將線程喚醒

3. 特殊之處

  1. Object 的 wait()/notify 方法需要獲取到對象鎖之後在同步代碼塊裏才能調用,而 LockSupport 不需要獲取鎖。所以使用 LockSupport 線程間不需要維護一個共享的同步對象,從而實現了線程間的解耦。

  2. unark()方法可提前 park()方法調用,所以不需要擔心線程間執行的先後順序。

  3. 多次調用 unpark()方法和調用一次 unpark()方法效果一樣,因爲 unpark 方法是直接將_counter 賦值爲 1,而不是加 1。

  4. 許可不可重入,也就是說只能調用一次 park()方法,如果多次調用 park()線程會一直阻塞。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章