首頁 > 軟體

Java同步鎖Synchronized底層原始碼和原理剖析(推薦)

2022-05-24 18:01:55

1 synchronized場景回顧

目標:
synchronized回顧(鎖分類–>多執行緒)
概念
synchronized:是Java中的關鍵字,是一種同步鎖。
Java中鎖分為以下幾種:
樂觀鎖、悲觀鎖(syn)
獨享鎖(syn)、共用鎖
公平鎖、非公平鎖(syn)
互斥鎖(syn)、讀寫鎖
可重入鎖(syn)
分段鎖
synchronized JDK1.6鎖升級(無鎖 -> 偏向鎖 (非鎖)-> 輕量級鎖 -> 重量級鎖(1.6前都是)【面試常問】
tips:
為什麼用到鎖?大家肯定會想到多執行緒(並行)
接下來,我們一起簡單回顧下多執行緒特性
多執行緒特性回顧(面試常問)
原子性:指一個操作或者多個操作,要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執

可見性:是指多個執行緒存取一個資源時,該資源的狀態、值資訊等對於其他執行緒都是可見的。
有序性:指程式中程式碼的執行順序 (編譯器會重排)

原子性實現回顧
保證了原子性?

com.syn.com.syn.th.SyncAtomicity

package com.syn.com.syn.th;
import java.util.concurrent.TimeUnit;
/*
  目標:測試原子性問題
  1、呼叫正常(不加鎖)方法;兩個執行緒都可以正常執行
  2、呼叫加鎖方法,只能有一個執行緒正常執行,其他執行緒排隊等候
*/
public class SyncAtomicity {
  public static void main(String[] args) throws InterruptedException {
    SyncAtomicity syncAtomicity = new SyncAtomicity();
    //synchronized修飾實體方法
    //new Thread(()->syncAtomicity.testSYNC()).start();
    //new Thread(()->syncAtomicity.testSYNC()).start();
    //synchronized修飾靜態方法
    new Thread(() -> SyncAtomicity.testSYNCForStatic()).start();
    new Thread(() -> SyncAtomicity.testSYNCForStatic()).start();
    //正常方法
    //new Thread(() -> syncAtomicity.test()).start();
    //new Thread(() -> syncAtomicity.test()).start();
 }
  //加鎖方法
  public synchronized void testSYNC() {
    System.out.println("進入testSYNC方法>>>>>>>>>>>>>>>>>>>>>");
    try {
      //模擬方法體尚未執行完畢
      TimeUnit.HOURS.sleep(1);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
 }
  //加鎖方法
  public synchronized static void testSYNCForStatic() {
    System.out.println("進入testSYNC方法>>>>>>>>>>>>>>>>>>>>>");
    try {
      //模擬方法體尚未執行完畢
      TimeUnit.HOURS.sleep(1);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
 }
  //正常方法
  public void test() {
    System.out.println("進入test方法>>>>>>>>>>>>>>>>>>>>>");
    try {
      //模擬方法體尚未執行完畢
      TimeUnit.HOURS.sleep(1);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
 }
}

總結
我們發現在同一時刻確實只有一個執行緒進入,保證了原子性
這是什麼原理呢?

2 反組合尋找鎖實現原理

目標 通過javap反組合看一下synchronized到底是怎麼加鎖的

com.syn.BTest

public class BTest {
  private static Object object = new Object();
  public synchronized void testMethod() {
    System.out.println("Hello World -synchronized method ");
 }
  public static void main(String[] args) {
    synchronized (object) {
      System.out.println("Hello World -synchronized block ");
     
   }
 }
}

反組合後,我們將看到什麼?

JDK自帶的一個工具: javap ,對位元組碼進行反組合:

//com.syn.BTest
javap -v -c BTest.class

反組合後

解釋
被synchronized修飾的程式碼塊,多了兩個指令
monitorenter、monitorexit
即JVM使用monitorenter和monitorexit兩個指令實現同步

解釋
被synchronized修飾的方法;增加 了ACC_SYNCHRONIZED 修飾。會隱式呼叫monitorenter和
monitorexit。
monitorenter原理(重要)
monitorenter首先我們來看一下JVM規範中對於monitorenter的描述

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html

翻譯如下:
每一個物件都會和一個監視器monitor關聯。
監視器被佔用時會被鎖住,其他執行緒無法來獲取該monitor。
當JVM執行某個執行緒的某個方法內部的monitorenter時,它會嘗試去獲取當前物件對應的monitor的所有權。其過程如下:

  • 若monior的進入數為0,執行緒可以進入monitor,並將monitor的進入數置為1。當前執行緒成為
  • monitor的owner(所有者)
  • 若執行緒已擁有monitor的所有權,允許它重入monitor,則進入monitor的進入數加1
  • 若其他執行緒已經佔有monitor的所有權,那麼當前嘗試獲取monitor的所有權的執行緒會被阻塞,直
  • 到monitor的進入數變為0,才能重新嘗試獲取monitor的所有權。
  • monitorexit(重要)
  • 能執行monitorexit指令的執行緒一定是擁有當前物件的monitor的所有權的執行緒。
  • 執行monitorexit時會將monitor的進入數減1。當monitor的進入數減為0時,當前執行緒退出

monitor,不再擁有monitor的所有權,此時其他被這個monitor阻塞的執行緒可以嘗試去獲取這個

monitor的所有權

monitorexit釋放鎖。

monitorexit插入在方法結束處和異常處,JVM保證每個monitorenter必須有對應的monitorexit。

tips(重要)

  • 關於monitorenter和monitorexit描述

上面文字太多,杜絕去念!!!!!!
用圖說話!!!! !!!!!!!!

類:com.syn.BTest

public static void main(String[] args) {
    synchronized (object) {
      System.out.println("Hello World -synchronized block ");
   }
 }

總結:
通過上面的流程我們發現
1、synchronized是靠Monitor關聯拿到鎖的
2、如果競爭的時候拿不到鎖,執行緒就去競爭佇列
3、如果拿到鎖了,第二次拿,它又拿到鎖,其他執行緒進入阻塞佇列
4、如果拿到鎖的執行緒呼叫了wait方法,其他執行緒進入等待佇列
5、釋放鎖,需要將計數器減減操作
6、出現異常,也釋放鎖。

3 synchronized虛擬機器器原始碼

synchronized是Java中的關鍵字,無法通過JDK原始碼檢視它的實現,它是由JVM提供支援的,所以如果想要了解具體的實現需要檢視JVM原始碼

目標:JVM虛擬機器器原始碼下載

http://hg.openjdk.java.net/jdk8/jdk8/hotspot/
或者
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/archive/tip.zip

解壓檢視即可,無需環境搭建

3.1 HotSpot原始碼Monitor生成

目標: 通過JVM虛擬機器器原始碼分析synchronized監視器Monitor是怎麼生成的
tips:
c++原始碼只看重點、弄懂原理
c++重要嗎?不重要
但是面試時很重要,面試過去了就不重要!!!!!!!!!!!!
學別人不會的東西你才有價值!!!!你會、大家都會,沒啥意思!!
在HotSpot虛擬機器器中,monitor監視器是由ObjectMonitor實現的。
構造器程式碼src/share/vm/runtime/objectMonitor.hpp
hpp可以include包含cpp的東西,兩者都是c++的程式碼

//構造器
ObjectMonitor() {
_header = NULL;
_count = 0;
_waiters = 0,
_recursions = 0; // 遞迴:執行緒的重入次數,典型的System.out.println
_object = NULL; // 對應synchronized (object)對應裡面的object
_owner = NULL; // 標識擁有該monitor的執行緒
_WaitSet = NULL; // 因為呼叫object.wait()方法而被阻塞的執行緒會被放在該佇列中
_WaitSetLock = 0 ;
_Responsible = NULL;
_succ = NULL;
_cxq = NULL; // 競爭佇列,所有請求鎖的執行緒首先會被放在這個佇列中
FreeNext = NULL;
_EntryList = NULL; // 阻塞;第二輪競爭鎖仍然沒有搶到的執行緒(偏向/可重入)
_SpinFreq = 0;
_SpinClock = 0;
OwnerIsThread = 0;
}

結論:正好印證了上面的流程圖

3.2 HotSpot原始碼之Monitor競爭

目標: 通過JVM虛擬機器器原始碼分析synchronized多個執行緒搶奪鎖,拿到鎖之後要幹什麼?

monitorenter指令執行:
JVM原始碼:src/share/vm/interpreter/interpreterRuntime.cpp
JVM函數: InterpreterRuntime::monitorenter函數

//鎖競爭InterpreterRuntime::monitorenter
IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread,
BasicObjectLock* elem))
#ifdef ASSERT
 thread->last_frame().interpreter_frame_verify_monitor(elem);
#endif
 if (PrintBiasedLockingStatistics) {
  Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
}
 Handle h_obj(thread, elem->obj());
 assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
    "must be NULL or an object");
 //偏向鎖(非鎖:jdk14廢棄)
 if (UseBiasedLocking) {
  // Retry fast entry if bias is revoked to avoid unnecessary inflation
  ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
} else {
 // 重量級鎖,最終呼叫了objectMonitor.cpp中的ObjectMonitor::enter
  ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
 ...略

最終呼叫objectMonitor.cpp檔案中的 ObjectMonitor::enter

src/share/vm/runtime/objectMonitor.cpp

//重量級鎖入口
void ATTR ObjectMonitor::enter(TRAPS) {
 Thread * const Self = THREAD ;
 void * cur ;
// 1、通過CAS(原子操作)操作嘗試把monitor的_owner欄位設定為當前執行緒(開始競爭)
 cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
 if (cur == NULL) {
  // Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
  assert (_recursions == 0  , "invariant") ;
  assert (_owner    == Self, "invariant") ;
  // CONSIDER: set or assert OwnerIsThread == 1
  return ;
}
// 2、拿到鎖;計數+1,recursions++
 if (cur == Self) {
  _recursions ++ ;//第一次進入(計數+1)
  return ;
}
 if (Self->is_lock_owned ((address)cur)) {
  assert (_recursions == 0, "internal state error");
  _recursions = 1 ;
  _owner = Self ;
  OwnerIsThread = 1 ;
  return ;
}
 assert (Self->_Stalled == 0, "invariant") ;
 Self->_Stalled = intptr_t(this) ;
 if (Knob_SpinEarly && TrySpin (Self) > 0) {
  assert (_owner == Self   , "invariant") ;
  assert (_recursions == 0  , "invariant") ;
  assert (((oop)(object()))->mark() == markOopDesc::encode(this),
"invariant") ;
  Self->_Stalled = 0 ;
  return ;
}
 assert (_owner != Self     , "invariant") ;
 assert (_succ  != Self     , "invariant") ;
 assert (Self->is_Java_thread() , "invariant") ;
 JavaThread * jt = (JavaThread *) Self ;
 assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
 assert (jt->thread_state() != _thread_blocked  , "invariant") ;
 assert (this->object() != NULL , "invariant") ;
 assert (_count >= 0, "invariant") ;
 Atomic::inc_ptr(&_count);
 EventJavaMonitorEnter event;
{
  JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
  DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
  if (JvmtiExport::should_post_monitor_contended_enter()) {
   JvmtiExport::post_monitor_contended_enter(jt, this);
 }
  OSThreadContendState osts(Self->osthread());
  ThreadBlockInVM tbivm(jt);
  Self->set_current_pending_monitor(this);
  for (;;) {
   jt->set_suspend_equivalent();
   // cleared by handle_special_suspend_equivalent_condition()
   // or java_suspend_self()
// 3、獲取鎖失敗的執行緒,則等待!!!!!!!!!!!!!!!!!!!!!!!!
   EnterI (THREAD) ;
   if (!ExitSuspendEquivalent(jt)) break ;
     _recursions = 0 ;
   _succ = NULL ;
   exit (false, Self) ;
   jt->java_suspend_self();
 }
  Self->set_current_pending_monitor(NULL);
}

總結

  • 通過CAS嘗試把monitor的owner欄位設定為當前執行緒。
  • 如果設定之前的owner指向當前執行緒,說明當前執行緒再次進入monitor,即重入鎖,執行
  • recursions ++ ,記錄重入的次數。
  • 獲取鎖失敗的執行緒,則【等待】鎖的釋放。
  • 一句話總結:自旋拿鎖、拿到+1 、拿不到等待(競爭佇列)

3.3 HotSpot原始碼之Monitor等待

目標: 通過JVM虛擬機器器原始碼分析synchronized拿不到鎖的執行緒他們都去幹什麼了?

還是 /objectMonitor.cpp
還是EnterI函數
路徑:src/share/vm/runtime/objectMonitor.cpp的

//拿不到鎖的執行緒他們都去幹什麼了??
void ATTR ObjectMonitor::EnterI (TRAPS) {
  Thread * Self = THREAD ;
  assert (Self->is_Java_thread(), "invariant") ;
  assert (((JavaThread *) Self)->thread_state() == _thread_blocked  ,
"invariant") ;
 // 沒拿到鎖,還是要嘗試TryLock一次
  if (TryLock (Self) > 0) {
   //拿到鎖執行,在返回
    assert (_succ != Self       , "invariant") ;
    assert (_owner == Self       , "invariant") ;
    assert (_Responsible != Self    , "invariant") ;
    return ;//成功獲取
 }
  DeferredInitialize () ;
 //沒拿到鎖,開始TrySpin自旋(CAS,while迴圈)
  if (TrySpin (Self) > 0) {
    assert (_owner == Self    , "invariant") ;
    assert (_succ != Self     , "invariant") ;
    assert (_Responsible != Self , "invariant") ;
    return ;
 }
  assert (_succ  != Self      , "invariant") ;
  assert (_owner != Self      , "invariant") ;
  assert (_Responsible != Self   , "invariant") ;
// 實在拿不到鎖;當前執行緒被封裝成ObjectWaiter物件node,狀態設定成ObjectWaiter::TS_CXQ
//即將放入競爭佇列
  ObjectWaiter node(Self) ;
  Self->_ParkEvent->reset() ;
  node._prev  = (ObjectWaiter *) 0xBAD ;
  node.TState  = ObjectWaiter::TS_CXQ ;
  ObjectWaiter * nxt ;
  for (;;) {
   node._next = nxt = _cxq ;
    //使用核心函數cmpxchg_ptr 將沒有拿到鎖執行緒(node)放到競爭佇列
    if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
    if (TryLock (Self) > 0) {
      assert (_succ != Self     , "invariant") ;
      assert (_owner == Self    , "invariant") ;
      assert (_Responsible != Self , "invariant") ;
      return ;
   }
 }
  if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
    Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
 }
  TEVENT (Inflated enter - Contention) ;
  int nWakeups = 0 ;
  int RecheckInterval = 1 ;
//將競爭佇列執行緒掛起
  for (;;) {
// 執行緒在被掛起前做一下掙扎,看能不能獲取到鎖
    if (TryLock (Self) > 0) break ;
    assert (_owner != Self, "invariant") ;
    if ((SyncFlags & 2) && _Responsible == NULL) {
     Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
   }
    // park self
    if (_Responsible == Self || (SyncFlags & 1)) {
      TEVENT (Inflated enter - park TIMED) ;
      Self->_ParkEvent->park ((jlong) RecheckInterval) ;
      // Increase the RecheckInterval, but clamp the value.
      RecheckInterval *= 8 ;
      if (RecheckInterval > 1000) RecheckInterval = 1000 ;
   } else {
      TEVENT (Inflated enter - park UNTIMED) ;
     // 掛起!!!!!!::通過park將當前執行緒掛起(不被執行了),等待被喚
醒!!!!!!!!!!!
      Self->_ParkEvent->park() ;
   }
  //當該執行緒被喚醒時,執行TryLock----->ObjectMonitor::TryLoc 
!!!!!!!!!!!!!!!!!!!!!
    if (TryLock(Self) > 0) break ;

當該執行緒被喚醒時,會從掛起的點繼續執行,通過 ObjectMonitor::TryLock 嘗試獲取鎖
總結
4. 競爭失敗的執行緒被封裝成ObjectWaiter物件node,狀態設定成ObjectWaiter::TS_CXQ(競爭隊
列)
5. 在for迴圈中,通過CAS把node節點push到_cxq列表中,(競爭佇列)
6. node節點push到_cxq列表之後,通過自旋嘗試獲取鎖,如果還是沒有獲取到鎖,則通過park將當
前執行緒掛起,等待被喚醒。
7. 當該執行緒被喚醒時,會從掛起的點繼續執行,通過 ObjectMonitor::TryLock 嘗試獲取鎖。

一句話總結:沒拿到,嘗試拿一次、在自旋去拿、實在拿不到就去競爭佇列、等待喚醒

3.4 HotSpot原始碼之Monitor釋放

目標: 通過JVM虛擬機器器原始碼分析synchronized拿到鎖的執行緒最後是怎麼釋放鎖的?

執行monitorexit指令
還是 /objectMonitor.cpp
裡面的exit函數
Osrc/share/vm/runtime/objectMonitor.cpp

//執行緒釋放呼叫exit方法
void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
 Thread * Self = THREAD ;
 if (THREAD != _owner) {
  if (THREAD->is_lock_owned((address) _owner)) {
   assert (_recursions == 0, "invariant") ;
   _owner = THREAD ;
   _recursions = 0 ;
   OwnerIsThread = 1 ;
  } else {
   TEVENT (Exit - Throw IMSX) ;
   assert(false, "Non-balanced monitor enter/exit!");
   if (false) {
     THROW(vmSymbols::java_lang_IllegalMonitorStateException());
   }
   return;
  }
 }
//_recursions計數不等於0;說明還沒出程式碼塊;進入減減操作,
 if (_recursions != 0) {
  _recursions--;     // this is simple recursive enter
  TEVENT (Inflated exit - recursive) ;
  return ;
 }
 if ((SyncFlags & 4) == 0) {
    _Responsible = NULL ;
 }
#if INCLUDE_TRACE
 if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
  _previous_owner_tid = SharedRuntime::get_java_tid(Self);
 }
#endif
 for (;;) {
   assert (THREAD == _owner, "invariant") ;
   if (Knob_ExitPolicy == 0) {
    OrderAccess::release_store_ptr (&_owner, NULL) ;  // drop the lock
    OrderAccess::storeload() ;             // See if we need to
wake a successor
    if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
      TEVENT (Inflated exit - simple egress) ;
      return ;
    }
    TEVENT (Inflated exit - complex egress) ;
    if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
      return ;
    }
    TEVENT (Exit - Reacquired) ;
  } else {
    if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
      OrderAccess::release_store_ptr (&_owner, NULL) ;  // drop the lock
      OrderAccess::storeload() ;
      // Ratify the previously observed values.
      if (_cxq == NULL || _succ != NULL) {
        TEVENT (Inflated exit - simple egress) ;
        return ;
     }
      if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
       TEVENT (Inflated exit - reacquired succeeded) ;
       return ;
     }
      TEVENT (Inflated exit - reacquired failed) ;
    } else {
      TEVENT (Inflated exit - complex egress) ;
    }
  }
   guarantee (_owner == THREAD, "invariant") ;
// 計數為0;開始喚醒cq競爭佇列、enteryList阻塞佇列
   ObjectWaiter * w = NULL ;//w就是被喚醒的執行緒
   int QMode = Knob_QMode ;
// qmode = 2:直接繞過EntryList阻塞佇列,從cxq(競爭)佇列中獲取執行緒用於競爭鎖
   if (QMode == 2 && _cxq != NULL) {
     w = _cxq ;
     assert (w != NULL, "invariant") ;
     assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
     ExitEpilog (Self, w) ;
     return ;
  }
// qmode =3:cxq(競爭)佇列插入EntryList(阻塞)尾部;
   if (QMode == 3 && _cxq != NULL) {
     w = _cxq ;
     for (;;) {
      assert (w != NULL, "Invariant") ;
      ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL,
&_cxq, w) ;
      if (u == w) break ;
      w = u ;
    }
     assert (w != NULL       , "invariant") ;
     ObjectWaiter * q = NULL ;
     ObjectWaiter * p ;
     for (p = w ; p != NULL ; p = p->_next) {
       guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
       p->TState = ObjectWaiter::TS_ENTER ;
       p->_prev = q ;
       q = p ;
    }
     // Append the RATs to the EntryList
     // TODO: organize EntryList as a CDLL so we can locate the tail in
constant-time.
     ObjectWaiter * Tail ;
     for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail =
Tail->_next) ;
     if (Tail == NULL) {
       _EntryList = w ;
    } else {
       Tail->_next = w ;
       w->_prev = Tail ;
    }
  }
// qmode =4:cxq佇列插入到_EntryList頭部
   if (QMode == 4 && _cxq != NULL) {
     // Aggressively drain cxq into EntryList at the first opportunity.
     // This policy ensure that recently-run threads live at the head of
EntryList.
     // Drain _cxq into EntryList - bulk transfer.
     // First, detach _cxq.
     // The following loop is tantamount to: w = swap (&cxq, NULL)
     w = _cxq ;
     for (;;) {
      assert (w != NULL, "Invariant") ;
      ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL,
&_cxq, w) ;
      if (u == w) break ;
      w = u ;
    }
     assert (w != NULL       , "invariant") ;
     ObjectWaiter * q = NULL ;
     ObjectWaiter * p ;
     for (p = w ; p != NULL ; p = p->_next) {
       guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
       p->TState = ObjectWaiter::TS_ENTER ;
       p->_prev = q ;
       q = p ;
    }
     // Prepend the RATs to the EntryList
     if (_EntryList != NULL) {
       q->_next = _EntryList ;
       _EntryList->_prev = q ;
    }
     _EntryList = w ;
     // Fall thru into code that tries to wake a successor from EntryList
  }
   w = _EntryList ;
   if (w != NULL) {
     assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
     ExitEpilog (Self, w) ;//喚醒w!!!!!!!!!!!!!!!!!!!!!! ------->當前
類的ExitEpilog
     return ;
  }

實現如下

void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
assert (_owner == Self, "invariant") ;
_succ = Knob_SuccEnabled ? Wakee->_thread : NULL ;
ParkEvent * Trigger = Wakee->_event ;
Wakee = NULL ;
// Drop the lock
OrderAccess::release_store_ptr (&_owner, NULL) ;
OrderAccess::fence() ; // ST _owner vs LD in
unpark()
if (SafepointSynchronize::do_call_back()) {
TEVENT (unpark before SAFEPOINT) ;
}
DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
  // 喚醒之前被park()掛起的執行緒.
 Trigger->unpark() ;// invoke ObjectMonitor::EnterI 方法,繼續競爭
   if (ObjectMonitor::_sync_Parks != NULL) {
   ObjectMonitor::_sync_Parks->inc() ;
 }
}

被喚醒的執行緒,回到 ObjectMonitor::EnterI (TRAPS) 的第600行,繼續執行monitor 的競爭。

// park self
if (_Responsible == Self || (SyncFlags & 1)) {
TEVENT (Inflated enter - park TIMED) ;
Self->_ParkEvent->park ((jlong) RecheckInterval) ;
// Increase the RecheckInterval, but clamp the value.
RecheckInterval *= 8 ;
if (RecheckInterval > 1000) RecheckInterval = 1000 ;
} else {
TEVENT (Inflated enter - park UNTIMED) ;
Self->_ParkEvent->park() ;
}
//喚醒之後就開始搶奪鎖
if (TryLock(Self) > 0) break ;

TryLock方 法實現如下:

//執行緒嘗試獲取鎖(or 執行緒被喚醒後獲取)
int ObjectMonitor::TryLock (Thread * Self) {
 for (;;) {
   void * own = _owner ;
   if (own != NULL) return 0 ;
   //獲取
   if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
    // Either guarantee _recursions == 0 or set _recursions = 0.
    assert (_recursions == 0, "invariant") ;
    assert (_owner == Self, "invariant") ;
   // 嘗試拿到鎖返回1
    return 1 ;
  }
//拿不到鎖返回-1
   if (true) return -1 ;
 }
}

總結
1、先進入減減操作,直到為0
2、為0後,喚醒競爭佇列的執行緒
3、喚醒執行緒後,繼續爭奪鎖,迴圈前面的步驟(鎖競爭-----等待----釋放)
一句話總結:釋放後,進入減減操作、直到為0然後喚醒佇列,讓他們去爭奪鎖,迴圈前面步驟

到此這篇關於Java同步鎖Synchronized底層原始碼和原理剖析的文章就介紹到這了,更多相關Java同步鎖Synchronized內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com