淺析LockSupport實現原理

微信公衆號:MyClass社區
若有問題或建議,請公衆號留言java

LockSupport介紹

     在閱讀開源項目的的時候,常常看到有人使用LockSupport,咱們今天來看一下它的使用和基本原理。首先,簡單的介紹一下LockSupport,它是併發包中的一個線程阻塞工具類,LockSupport提供park()和unpark()兩個方法實現阻塞線程和解除線程阻塞。下面看看它與wait和notify使用上有何區別?微信

LockSupport的使用

     咱們知道Object類也能夠實現阻塞和喚醒,wait和notify只能在同步代碼塊或者同步方法中調用,這裏是爲了保證多線程object操做wait和notify的原子性。多線程

public void waitAndNotify() throws Exception {
    final Object obj = new Object();
    Thread testThread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("do task");
            System.out.println("wait---");
            synchronized (obj){
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("continue do task");
        }
    });
    testThread.start();
    //這裏sleep是爲了保證已經阻塞
    Thread.sleep(1000);
    synchronized (obj){
        System.out.println("notify--------");
        obj.notify();
    }
}
併發

      下面是LockSupport的使用,LockSupport.park()阻塞線程,而後調用unpark進行喚醒,不須要像wait/notify那樣先要保證進入wait,才能喚醒線程,不然會無限等待。LockSupport若是先調用unpark後,線程再調用park是不會被一直阻塞的,使用起來更加簡單靈活。jvm

public void lockSupportTest({
    final Object obj = new Object();
    Thread testThread = new Thread(new Runnable() {
        @Override
        public void run(
{
            System.out.println("do task");
            System.out.println("wait---");
            LockSupport.park();
            System.out.println("continue do task");
        }
    });
    testThread.start();
    //這裏sleep是爲了保證park成功
    Thread.sleep(1000);
    System.out.println("notify--------");
    LockSupport.unpark(testThread);
}
ide

以上的執行效果:函數

do task
wait---
notify--------
continue do task
工具

1.LockSupport不須要在同步代碼塊裏 。因此線程間也不須要維護一個共享的同步對象了,實現了線程間的解耦。
2.notify和notifyAll,通常的若是多個線程都對同一個對象進行阻塞,notify()是不肯定喚醒哪個線程的等待。
3.unpark函數能夠先於park調用,因此不須要擔憂線程間的執行的前後順序。
4.wait/notify和notifyAll和LockSupport阻塞的線程是相互隔離的,object阻塞的是對象維度,不一樣的線程能夠對同一個對象進行操做,而LockSupport是線程維度的阻塞,因此不會交叉影響,你們能夠本身試一試。spa

LockSupport實現原理

wait方法實現

      首先說一下wait,它是在同步機制中的一個操做,須要放棄同步對象鎖的monitor,monitor信息保存在對象頭信息中,以前講過synchronized鎖信息也是保存在對象頭信息(Mark Word)中,當線程調用wait的時候,將線程放入該對象鎖ObjectMonitor的等待喚醒集合wait-set中來實現將線程掛起。.net

notify方法實現

      lock.notify()方法底層也是經過ObjectMonitor的void notify()實現,獲取對象的信息的WaitSet列表中的第一個節點。這裏須要注意的是,在jdk的notify方法註釋是隨機喚醒一個線程,實際上是第一個ObjectWaiter節點

LockSuppor實現

/**
 * 若是給定線程的許可尚不可用,則使其可用。
 * 若是線程調用了park,調用unpark將解除其阻塞狀態。
 * 若是沒有park,保證下一次調用 park也不會受阻塞。
 * 啓動了線程,調用纔會有效果,否哦無效。
 * @param thread: 要執行 unpark 操做的線程;該參數爲 null 表示此操做沒有任何效果。
 */

public static void unpark(Thread thread{
    if (thread != null)
        UNSAFE.unpark(thread);
}

/**
 * 爲了線程調度,在許可可用以前阻塞當前線程。
 * 若是許可可用,則使用該許可,而且該調用當即返回;
 * 不然,爲線程調度禁用當前線程,並在發生如下三種狀況之一之前,使其處於休眠狀態:
 *  1. 其餘某個線程將當前線程做爲目標調用 unpark
 *  2. 其餘某個線程中斷當前線程
 *  3. 該調用不合邏輯地(即毫無理由地)返回
 */

public static void park({
    UNSAFE.park(false0L);
}

LockSuppor的park/unpark方法實際上是操做Unsafe類裏的函數。

//參數線程
public native void unpark(Thread jthread);
//isAbsolute參數是指明時間是絕對的,仍是相對的。
public native void park(boolean isAbsolute, long time);

      經過openjdk的源碼看看其native實現,HotSpot裏park/unpark的實現,每一個java線程都有一個Parker實例,Parker類是這樣定義的,在Parker類裏的_counter字段,就是用來記錄線程是否阻塞狀態的,網上不少人稱之爲所謂的「許可」狀態,具體邏輯就不擴展了,有機會能夠深刻了解一下底層jvm的實現原理。

class Parker : public os::PlatformParker {
private:
  volatile int _counter ;
  ...
public:
  void park(bool isAbsolute, jlong time);
  void unpark();
  ...
}
class PlatformParker : public CHeapObj<mtInternal> {
  protected:
    pthread_mutex_t _mutex [1] ;
    pthread_cond_t  _cond  [1] ;
    ...

總結

  1. LockSuppor真正解耦了線程之間的同步,線程之間再也不須要一個Object或者其它變量來存儲狀態;

  2. 當調用park時,先嚐試直接可否拿到「許可」,即_counter>0時,若是成功,則把_counter設置爲0,並返回;

  3. 當unpark時,直接設置_counter爲1,而且返回。若是_counter以前的值是0,則還要喚醒在park中等待的線程;

  4. 簡單的理解就是維護_counter的變量,當park時,這個變量置爲了0,表明當前線程阻塞了,等待許可,當unpark時,這個變量置爲1,則線程獲取許可表明喚醒繼續執行;

  5. 屢次調用unpark方法和調用一次unpark方法效果同樣,由於都是直接將_counter賦值爲1,而不是加1。

本文分享自微信公衆號 - MyClass社區(MyClass_ZZ)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索