并發(fā)編程-(3)-LockSupport

死神---井上織姬

目錄:

  • 1、LockSupport工具定位:
  • 2、LockSupport工具定義:
  • 3、LockSupport常用方法:
    • 3.1、阻塞方法
    • 3.2、喚醒線程
    • 3.3、demo分析blocker
    • 3.4、分析LockSupport.parkNanos(long)、LockSupport.parkUnitl(long):
  • 4 、源碼分析:
    • 4.1、park()分析
    • 4.2、unpark()分析

1、LockSupport工具定位

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

2、LockSupport工具定義

??????LockSupport定義了一組以park開(kāi)頭的方法來(lái)阻塞當(dāng)前線程,unpark來(lái)喚醒被阻塞的線程。

3、LockSupport常用方法

3.1、阻塞方法
  • 1、void park():阻塞當(dāng)前線程。如果調(diào)用unpark方法或者當(dāng)前線程被中斷,可以從park()方法中返回;Thread.interrupte()詳解一下?<<<<<<傳送門(mén)
  • 2、void park(Object blocker):功能同方法1,入?yún)⒃黾右粋€(gè)Object對(duì)象,用來(lái)記錄導(dǎo)致線程阻塞的阻塞對(duì)象,方便進(jìn)行問(wèn)題排查;
  • 3、void parkNanos(long nanos):阻塞當(dāng)前線程,最長(zhǎng)不超過(guò)nanos納秒,增加了超時(shí)返回的特性;
  • 4、void parkNanos(Object blocker, long nanos):功能同方法3,入?yún)⒃黾右粋€(gè)Object對(duì)象,用來(lái)記錄導(dǎo)致線程阻塞的阻塞對(duì)象,方便進(jìn)行問(wèn)題排查;
  • 5、void parkUntil(long deadline):阻塞當(dāng)前線程,知道deadline(絕對(duì)時(shí)間);
  • 6、void parkUntil(Object blocker, long deadline):功能同方法5,入?yún)⒃黾右粋€(gè)Object對(duì)象,用來(lái)記錄導(dǎo)致線程阻塞的阻塞對(duì)象,方便進(jìn)行問(wèn)題排查;
3.2、喚醒線程
  • 1、void unpark(Thread thread):喚醒處于阻塞狀態(tài)的指定線程;
3.3、demo分析blocker:
/**
 * @program: jvmproject
 * @description: LockSupport場(chǎng)景和方法
 * @author: biudefu
 * @create: 2019-08-24
 **/
public class LockSupportMain {

    private static final Object u = new Object();

    public static void main(String[] args) throws InterruptedException {

        System.out.println("main線程 啟動(dòng)!");

        Thread t1 = new Thread(() -> {
            new LockSupportMain().blockCurrencyThread();
        }, "LockSupport_T1");
        t1.start();

        Thread.sleep(3 * 1000L);

        Thread t2 = new Thread(() -> {
            new LockSupportMain().blockCurrencyThreadByObject(u);
        }, "LockSupport_T2");
        t2.start();
        Thread.sleep(3*1000);

        System.out.println("main線程 退出!");

    }

    public void blockCurrencyThreadByObject(Object obj) {
        System.out.println("LockSupport.park() ---> 阻塞當(dāng)前線程!");
        LockSupport.park(obj);
        System.out.println("LockSupport.park() <--- 被喚醒!");
    }

    public void blockCurrencyThread() {
        System.out.println("Thread name : " + Thread.currentThread().getName() + " call LockSupport.park() ---> 阻塞當(dāng)前線程!");
        LockSupport.park();
        System.out.println("Thread name : " + Thread.currentThread().getName() + " call LockSupport.park() <--- 被喚醒!");
    }

}

"LockSupport_T2" #12 prio=5 os_prio=31 tid=0x00007fe92e86c000 nid=0x5703 waiting on condition [0x0000700006b93000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x000000076aca4428> (a java.lang.Object)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at com.lyc.jvm.concurrent.locksupport.LockSupportMain.blockCurrencyThreadByObject(LockSupportMain.java:63)
    at com.lyc.jvm.concurrent.locksupport.LockSupportMain.lambda$main$1(LockSupportMain.java:30)
    at com.lyc.jvm.concurrent.locksupport.LockSupportMain$$Lambda$2/793589513.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

"LockSupport_T1" #11 prio=5 os_prio=31 tid=0x00007fe92e018000 nid=0x5603 waiting on condition [0x0000700006a90000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304)
    at com.lyc.jvm.concurrent.locksupport.LockSupportMain.blockCurrencyThread(LockSupportMain.java:69)
    at com.lyc.jvm.concurrent.locksupport.LockSupportMain.lambda$main$0(LockSupportMain.java:20)
    at com.lyc.jvm.concurrent.locksupport.LockSupportMain$$Lambda$1/1915910607.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

在jstack中可以看到- parking to wait for <0x000000076aca4428> (a java.lang.Object),方便進(jìn)行問(wèn)題排查。

3.4、分析LockSupport.parkNanos(long)、LockSupport.parkUnitl(long):
public static void main(String[] args) throws InterruptedException {

        System.out.println("main線程 啟動(dòng)!");

        //@003 LockSupport.parkNanos(long)與LockSupport.parkUntil(long);
        Thread t3 = new Thread(()->{
            blockUseNanos(10*1000*1000*1000l);
        },"LockSupport_T3_Nanos");
        Thread t4 = new Thread(()->{
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                Date myDate2 = dateFormat2.parse("2019-08-26 06:43:00");
                blockUseUntil(myDate2.getTime());
            } catch (ParseException e) {
                e.printStackTrace();
            }

        },"LockSupport_T3_Until");
        t3.start();
        t4.start();

        System.out.println("main線程 退出!");

    }

    private static void blockUseNanos(long l) {
        System.out.println(DateUtil.getNowYYMMDDHHMMSS()+"LockSupport.parkNanos(long) ---> 阻塞當(dāng)前線程!times:"+(l/1000/1000/1000)+"s");
        LockSupport.parkNanos(l);
        System.out.println(DateUtil.getNowYYMMDDHHMMSS()+"LockSupport.parkNanos(long) <--- 被喚醒!");
    }

    private static void blockUseUntil(long l) {
        System.out.println(DateUtil.getNowYYMMDDHHMMSS()+"LockSupport.parkUntil(long) ---> 阻塞當(dāng)前線程!喚醒時(shí)間:" + DateUtil.timesConvertDate(l));
        LockSupport.parkUntil(l);
        System.out.println(DateUtil.getNowYYMMDDHHMMSS()+"LockSupport.parkUntil(long) <--- 被喚醒!");
    }
main線程 啟動(dòng)!
main線程 退出!
2019-08-26 06:48:49,LockSupport.parkNanos(long) ---> 阻塞當(dāng)前線程!times:10s
2019-08-26 06:48:49,LockSupport.parkUntil(long) ---> 阻塞當(dāng)前線程!喚醒時(shí)間:2019-08-26 06:49:00,
2019-08-26 06:48:59,LockSupport.parkNanos(long) <--- 被喚醒!
2019-08-26 06:49:00,LockSupport.parkUntil(long) <--- 被喚醒!

4、LockSupport依賴底層sun.misc.Unsafe

4.1、Unsafe.park和Unsafe.unpark的底層實(shí)現(xiàn)原理:

Unsafe類(lèi)中函數(shù)基本都是Native屬性, 在虛擬機(jī)源代碼/hotspot/src/share/vm/prims/unsafe.cppUnsafe類(lèi)Native與c++語(yǔ)言函數(shù)之間對(duì)應(yīng)關(guān)系:

// These are the methods for 1.8.0
static JNINativeMethod methods_18[] = {
    {CC"getObject",        CC"("OBJ"J)"OBJ"",   FN_PTR(Unsafe_GetObject)},
    {CC"putObject",        CC"("OBJ"J"OBJ")V",  FN_PTR(Unsafe_SetObject)},
    {CC"getObjectVolatile",CC"("OBJ"J)"OBJ"",   FN_PTR(Unsafe_GetObjectVolatile)},
    {CC"putObjectVolatile",CC"("OBJ"J"OBJ")V",  FN_PTR(Unsafe_SetObjectVolatile)},

    DECLARE_GETSETOOP(Boolean, Z),
    DECLARE_GETSETOOP(Byte, B),
    DECLARE_GETSETOOP(Short, S),
    DECLARE_GETSETOOP(Char, C),
    DECLARE_GETSETOOP(Int, I),
    DECLARE_GETSETOOP(Long, J),
    DECLARE_GETSETOOP(Float, F),
    DECLARE_GETSETOOP(Double, D),

    DECLARE_GETSETNATIVE(Byte, B),
    DECLARE_GETSETNATIVE(Short, S),
    DECLARE_GETSETNATIVE(Char, C),
    DECLARE_GETSETNATIVE(Int, I),
    DECLARE_GETSETNATIVE(Long, J),
    DECLARE_GETSETNATIVE(Float, F),
    DECLARE_GETSETNATIVE(Double, D),

    {CC"getAddress",         CC"("ADR")"ADR,             FN_PTR(Unsafe_GetNativeAddress)},
    {CC"putAddress",         CC"("ADR""ADR")V",          FN_PTR(Unsafe_SetNativeAddress)},

    {CC"allocateMemory",     CC"(J)"ADR,                 FN_PTR(Unsafe_AllocateMemory)},
    {CC"reallocateMemory",   CC"("ADR"J)"ADR,            FN_PTR(Unsafe_ReallocateMemory)},
    {CC"freeMemory",         CC"("ADR")V",               FN_PTR(Unsafe_FreeMemory)},

    {CC"objectFieldOffset",  CC"("FLD")J",               FN_PTR(Unsafe_ObjectFieldOffset)},
    {CC"staticFieldOffset",  CC"("FLD")J",               FN_PTR(Unsafe_StaticFieldOffset)},
    {CC"staticFieldBase",    CC"("FLD")"OBJ,             FN_PTR(Unsafe_StaticFieldBaseFromField)},
    {CC"ensureClassInitialized",CC"("CLS")V",            FN_PTR(Unsafe_EnsureClassInitialized)},
    {CC"arrayBaseOffset",    CC"("CLS")I",               FN_PTR(Unsafe_ArrayBaseOffset)},
    {CC"arrayIndexScale",    CC"("CLS")I",               FN_PTR(Unsafe_ArrayIndexScale)},
    {CC"addressSize",        CC"()I",                    FN_PTR(Unsafe_AddressSize)},
    {CC"pageSize",           CC"()I",                    FN_PTR(Unsafe_PageSize)},

    {CC"defineClass",        CC"("DC_Args")"CLS,         FN_PTR(Unsafe_DefineClass)},
    {CC"allocateInstance",   CC"("CLS")"OBJ,             FN_PTR(Unsafe_AllocateInstance)},
    {CC"monitorEnter",       CC"("OBJ")V",               FN_PTR(Unsafe_MonitorEnter)},
    {CC"monitorExit",        CC"("OBJ")V",               FN_PTR(Unsafe_MonitorExit)},
    {CC"tryMonitorEnter",    CC"("OBJ")Z",               FN_PTR(Unsafe_TryMonitorEnter)},
    {CC"throwException",     CC"("THR")V",               FN_PTR(Unsafe_ThrowException)},
    {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z",  FN_PTR(Unsafe_CompareAndSwapObject)},
    {CC"compareAndSwapInt",  CC"("OBJ"J""I""I"")Z",      FN_PTR(Unsafe_CompareAndSwapInt)},
    {CC"compareAndSwapLong", CC"("OBJ"J""J""J"")Z",      FN_PTR(Unsafe_CompareAndSwapLong)},
    {CC"putOrderedObject",   CC"("OBJ"J"OBJ")V",         FN_PTR(Unsafe_SetOrderedObject)},
    {CC"putOrderedInt",      CC"("OBJ"JI)V",             FN_PTR(Unsafe_SetOrderedInt)},
    {CC"putOrderedLong",     CC"("OBJ"JJ)V",             FN_PTR(Unsafe_SetOrderedLong)},
    {CC"park",               CC"(ZJ)V",                  FN_PTR(Unsafe_Park)},
    {CC"unpark",             CC"("OBJ")V",               FN_PTR(Unsafe_Unpark)}
};

其中:park----->Unsafe_Park,unpark----->Unsafe_Unpark。

UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
  UnsafeWrapper("Unsafe_Park");
  EventThreadPark event;
#ifndef USDT2
  HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time);
#else /* USDT2 */
   HOTSPOT_THREAD_PARK_BEGIN(
                             (uintptr_t) thread->parker(), (int) isAbsolute, time);
#endif /* USDT2 */
  JavaThreadParkedState jtps(thread, time != 0);
  thread->parker()->park(isAbsolute != 0, time);
#ifndef USDT2
  HS_DTRACE_PROBE1(hotspot, thread__park__end, thread->parker());
#else /* USDT2 */
  HOTSPOT_THREAD_PARK_END(
                          (uintptr_t) thread->parker());
#endif /* USDT2 */
  if (event.should_commit()) {
    oop obj = thread->current_park_blocker();
    event.set_klass((obj != NULL) ? obj->klass() : NULL);
    event.set_timeout(time);
    event.set_address((obj != NULL) ? (TYPE_ADDRESS) cast_from_oop<uintptr_t>(obj) : 0);
    event.commit();
  }
UNSAFE_END

調(diào)用關(guān)系:thread->parker()->park(isAbsolute != 0, time)方法。
查看下thread和Parker關(guān)系/hotspot/src/share/vm/prims/runtime/thread.hpp(L1740)

  // JSR166 per-thread parker
private:
  Parker*    _parker;
public:
  Parker*     parker() { return _parker; }

可以看出, 每個(gè)thread類(lèi)中都包含一個(gè)Parker。
Parker定義在/hotspot/src/share/vm/runtime/park.hpp(L56), 定義如下:

class Parker : public os::PlatformParker {
private:
  volatile int _counter ;
  Parker * FreeNext ;
  JavaThread * AssociatedWith ; // Current association

public:
  Parker() : PlatformParker() {
    _counter       = 0 ;
    FreeNext       = NULL ;
    AssociatedWith = NULL ;
  }
protected:
  ~Parker() { ShouldNotReachHere(); }
public:
  // For simplicity of interface with Java, all forms of park (indefinite,
  // relative, and absolute) are multiplexed into one call.
  void park(bool isAbsolute, jlong time);
  void unpark();

  // Lifecycle operators
  static Parker * Allocate (JavaThread * t) ;
  static void Release (Parker * e) ;
private:
  static Parker * volatile FreeList ;
  static volatile int ListLock ;

};

Parker類(lèi)實(shí)際上在Linux系統(tǒng)下是用Posix線程庫(kù)pthread中的mutex(互斥量),condition(條件變量)來(lái)實(shí)現(xiàn)的,mutex和condition保護(hù)了一個(gè)_counter的變量,當(dāng)park時(shí),這個(gè)變量被設(shè)置為0,當(dāng)unpark時(shí),這個(gè)變量被設(shè)置為1。

4.1、分析park()過(guò)程:

以Linux系統(tǒng)實(shí)現(xiàn)為例:

void Parker::park(bool isAbsolute, jlong time) {
  // Ideally we'd do something useful while spinning, such
  // as calling unpackTime().
  // Optional fast-path check:
  // Return immediately if a permit is available.
  // We depend on Atomic::xchg() having full barrier semantics
  // since we are doing a lock-free update to _counter.
   //這里通過(guò)原子操作來(lái)完成_counter清零操作。 若_counter之前>0, 那么說(shuō)明之前該線程被unpark()過(guò), 就可以直接返回而不被阻塞。
  if (Atomic::xchg(0, &_counter) > 0) return;
  Thread* thread = Thread::current();
  assert(thread->is_Java_thread(), "Must be JavaThread");  //判斷一定的是java線程
  JavaThread *jt = (JavaThread *)thread; //類(lèi)強(qiáng)制轉(zhuǎn)化
  // Optional optimization -- avoid state transitions if there's an interrupt pending.
  // Check interrupt before trying to wait
  //進(jìn)入睡眠等待前先檢查是否有中斷信號(hào), 若有中斷信號(hào)也直接返回。
  if (Thread::is_interrupted(thread, false)) {
    return;
  }
  // Next, demultiplex/decode time arguments
  timespec absTime;
  //如果是按參數(shù)小于0,或者絕對(duì)時(shí)間,那么可以直接返回
  if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
    return;
  }
   //如果時(shí)間大于0,判斷阻塞超時(shí)時(shí)間或阻塞截止日期,同時(shí)將時(shí)間賦值給absTime
  if (time > 0) {
    unpackTime(&absTime, isAbsolute, time);
  }
  // Enter safepoint region
  // Beware of deadlocks such as 6317397.
  // The per-thread Parker:: mutex is a classic leaf-lock.
  // In particular a thread must never block on the Threads_lock while
  // holding the Parker:: mutex.  If safepoints are pending both the
  // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
  ThreadBlockInVM tbivm(jt);
  // Don't wait if cannot get lock since interference arises from
  // unblocking.  Also. check interrupt before trying wait
  //再次檢查, 如果有中斷信號(hào)。直接返回; 或者申請(qǐng)互斥鎖失敗,則直接返回pthread_mutex_trylock返回0。任何其他返回值都表示錯(cuò)誤。
  //函數(shù)pthread_mutex_trylock是POSIX 線程pthread_mutex_lock的非阻塞版本。
  if (Thread::is_interrupted(thread, false) || pthread_mutex_trylock(_mutex) != 0) {
    return;
  }
  //此時(shí)已經(jīng)通過(guò)_mutex將該代碼進(jìn)行了互斥操作, 那么直接對(duì)_counter都是安全的
  int status ;
  如果count>0, 說(shuō)明之前原子操作賦值為0沒(méi)有成功。 而_counter> 0, 線程可以直接不阻塞而返回
  if (_counter > 0)  { // no wait needed
     //將_counter直接清零
    _counter = 0;
    //釋放鎖并返回, 返回0代表釋放鎖成功
    status = pthread_mutex_unlock(_mutex);
    assert (status == 0, "invariant") ; //這里會(huì)去檢查一下是否成功了
    // Paranoia to ensure our locked and lock-free paths interact
    // correctly with each other and Java-level accesses.
    OrderAccess::fence(); //這個(gè)函數(shù)是HotSpot VM對(duì)JMM的內(nèi)存屏障一個(gè)具體的實(shí)現(xiàn)函數(shù);
    return;
  }
#ifdef ASSERT
  // Don't catch signals while blocked; let the running threads have the signals.
  // (This allows a debugger to break into the running thread.)
  sigset_t oldsigs;
  sigset_t* allowdebug_blocked = os::Linux::allowdebug_blocked_signals();
  pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);
#endif
  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
  jt->set_suspend_equivalent();
  // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
  assert(_cur_index == -1, "invariant");
     //若沒(méi)有超時(shí)時(shí)間,那么本線程將進(jìn)入睡眠狀態(tài)并釋放cpu、釋放對(duì)_mutex的鎖定,等待其他線程調(diào)用pthread_cond_signal喚醒該線程;喚醒后會(huì)獲取對(duì)_mutex的鎖定的鎖定
  if (time == 0) {
    _cur_index = REL_INDEX; // arbitrary choice when not timed
    status = pthread_cond_wait (&_cond[_cur_index], _mutex) ;
  } else {
    _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
     //開(kāi)始真正的阻塞,超時(shí)等待,或者其他線程pthread_cond_signal喚醒該線程
    status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;
    if (status != 0 && WorkAroundNPTLTimedWaitHang) {
      pthread_cond_destroy (&_cond[_cur_index]) ;
      pthread_cond_init    (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
    }
  }
  _cur_index = -1;
  assert_status(status == 0 || status == EINTR ||
                status == ETIME || status == ETIMEDOUT,
                status, "cond_timedwait");
#ifdef ASSERT
  pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
#endif
    //該線程被喚醒了, 同時(shí)也對(duì)_mutex加鎖了, 置位_counter是線程安全的
  _counter = 0 ;
  //解鎖_mutex
  status = pthread_mutex_unlock(_mutex) ;
  assert_status(status == 0, status, "invariant") ;
  // Paranoia to ensure our locked and lock-free paths interact
  // correctly with each other and Java-level accesses.
  OrderAccess::fence(); //內(nèi)存屏障
  // If externally suspended while waiting, re-suspend
  if (jt->handle_special_suspend_equivalent_condition()) {
    jt->java_suspend_self();
  }
}

Parker::park主要做了如下事情:

  • 檢查_(kāi)counter>0(別的線程調(diào)用過(guò)unpark), 則原子操作清零。線程不用睡眠并返回。
  • 檢查該線程是否有中斷信號(hào), 有的話,清掉并返回。
  • 嘗試通過(guò)pthread_mutex_trylock對(duì)_mutex加鎖來(lái)達(dá)到線程互斥。
  • 檢查_(kāi)counter是否>0, 若成立,說(shuō)明第一步原子清零操作失敗。檢查park是否設(shè)置超時(shí)時(shí)間, 若設(shè)置了通過(guò)safe_cond_timedwait進(jìn)行超時(shí)等待; 若沒(méi)有設(shè)置,調(diào)用pthread_cond_wait進(jìn)行阻塞等待。 這兩個(gè)函數(shù)都在阻塞等待時(shí)都會(huì)放棄cpu的使用。 直到別的線程調(diào)用pthread_cond_signal喚醒
  • 直接_counter=0清零。
  • 通過(guò)pthread_mutex_unlock釋放mutex的加鎖。
    需要了解下: safe_cond_timedwait/pthread_cond_wait在執(zhí)行之前肯定已經(jīng)獲取了鎖_mutex, 在睡眠前釋放了鎖, 在被喚醒之前, 首先再取喚醒鎖。
4.3、unpark()過(guò)程:
void Parker::unpark() {
  int s, status ;
  //首先是互斥獲取鎖
  status = pthread_mutex_lock(_mutex);
  assert (status == 0, "invariant") ;
  s = _counter;
  //只要把這個(gè)狀態(tài)置為1就行了,就是說(shuō)多次調(diào)用unpack()沒(méi)啥意義
  _counter = 1;
   //s只能為0,說(shuō)明沒(méi)有人調(diào)用unpark
  if (s < 1) {
    // thread might be parked
    if (_cur_index != -1) {
      // thread is definitely parked
      //線程已經(jīng)處于parker狀態(tài)了
      if (WorkAroundNPTLTimedWaitHang) {
       //pthread_cond_signal可以喚醒pthread_cond_wait()被&_cond[_cur_index]阻塞的線程
        status = pthread_cond_signal (&_cond[_cur_index]);
        assert (status == 0, "invariant");
        //解鎖
        status = pthread_mutex_unlock(_mutex);
        assert (status == 0, "invariant");
      } else {
        status = pthread_mutex_unlock(_mutex);
        assert (status == 0, "invariant");
        status = pthread_cond_signal (&_cond[_cur_index]);
        assert (status == 0, "invariant");
      }
    } else {
    //僅僅解鎖
      pthread_mutex_unlock(_mutex);
      assert (status == 0, "invariant") ;
    }
  } else {
    pthread_mutex_unlock(_mutex);
    assert (status == 0, "invariant") ;
  }
}

unpark()主要做了如下事情:

  • 首先獲取鎖_mutex。
  • 對(duì)_counter置為1, 而不管之前什么值, 這里說(shuō)明無(wú)論多少函數(shù)調(diào)用unpark(), 都是無(wú)效的, 只會(huì)記錄一次。
  • 檢查線程是否已經(jīng)被阻塞了, 若已經(jīng)阻塞了,調(diào)用pthread_cond_signal喚醒喚醒。
  • 釋放對(duì)_mutex的鎖定。

參考資料:

《深入理解Java虛擬機(jī)-2nd》
《Java 并發(fā)編程實(shí)戰(zhàn)》
《Java 并發(fā)編程的藝術(shù)》

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

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