Java同步锁Synchronized底层源码和原理剖析(推荐)

目录
  • 1 synchronized场景回顾
  • 2 反汇编寻找锁实现原理
  • 3 synchronized虚拟机源码
    • 3.1 HotSpot源码Monitor生成
    • 3.2 HotSpot源码之Monitor竞争
    • 3.3 HotSpot源码之Monitor等待
    • 3.4 HotSpot源码之Monitor释放

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#jvms-6.5.monitorenter

翻译如下:
每一个对象都会和一个监视器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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java 同步锁(synchronized)详解及实例

    Java 同步锁(synchronized)详解及实例 Java中cpu分给每个线程的时间片是随机的并且在Java中好多都是多个线程共用一个资源,比如火车卖票,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源.如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦.比如下面程序: package com.pakage.ThreadAndRunnable; public class Ru

  • Java对象级别与类级别的同步锁synchronized语法示例

    目录 1.对象级别的同步锁 2.类级别的同步锁 3.总结 Java synchronized 关键字 可以将一个代码块或一个方法标记为同步代码块.同步代码块是指同一时间只能有一个线程执行的代码,并且执行该代码的线程持有同步锁.synchronized关键字可以作用于 一个代码块 一种方法 当一个方法或代码块被声明为synchronized时,如果一个线程正在执行该synchronized 方法或代码块,其他线程会被阻塞,直到持有同步锁的线程释放.根据锁定的范围可以分为 类级别的锁可以防止多个线程

  • Java同步锁Synchronized底层源码和原理剖析(推荐)

    目录 1 synchronized场景回顾 2 反汇编寻找锁实现原理 3 synchronized虚拟机源码 3.1 HotSpot源码Monitor生成 3.2 HotSpot源码之Monitor竞争 3.3 HotSpot源码之Monitor等待 3.4 HotSpot源码之Monitor释放 1 synchronized场景回顾 目标:synchronized回顾(锁分类–>多线程)概念synchronized:是Java中的关键字,是一种同步锁.Java中锁分为以下几种:乐观锁.悲观锁(

  • 解决java 查看JDK中底层源码的实现方法

    1.点 "window"-> "Preferences" -> "Java" -> "Installed JRES"2.此时"Installed JRES"右边是列表窗格,列出了系统中的 JRE 环境,选择你的JRE,然后点边上的 "Edit...", 会出现一个窗口(Edit JRE)3.选中rt.jar文件的这一项:"c:\program files\ja

  • java锁机制ReentrantLock源码实例分析

    目录 一:简述 二:ReentrantLock类图 三:流程简图 四:源码分析 lock()源码分析: 非公平实现: 公平锁实现: tryAcquire()方法 公平锁实现: 非公平锁实现: addWaiter() acquireQueued() shouldParkAfterFailedAcquire() parkAndCheckInterrupt() unlock()方法源码分析: tryRelease() unparkSuccessor() 五:总结 一:简述 ReentrantLock是

  • Java并发系列之ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可见性.在大多数情况下,这些机制都能很好地完成工作,但却无法实现一些更高级的功能,例如,无法中断一个正在等待获取锁的线程,无法实现限定时间的获取锁机制,无法实现非阻塞结构的加锁规则等.而这些更灵活的加锁机制通常都能够提供更好的活跃性或性能.因此,在Java5.0中增加了一种新的机制:Reentrant

  • Java并发系列之AbstractQueuedSynchronizer源码分析(概要分析)

    学习Java并发编程不得不去了解一下java.util.concurrent这个包,这个包下面有许多我们经常用到的并发工具类,例如:ReentrantLock, CountDownLatch, CyclicBarrier, Semaphore等.而这些类的底层实现都依赖于AbstractQueuedSynchronizer这个类,由此可见这个类的重要性.所以在Java并发系列文章中我首先对AbstractQueuedSynchronizer这个类进行分析,由于这个类比较重要,而且代码比较长,为了

  • Java并发系列之Semaphore源码分析

    Semaphore(信号量)是JUC包中比较常用到的一个类,它是AQS共享模式的一个应用,可以允许多个线程同时对共享资源进行操作,并且可以有效的控制并发数,利用它可以很好的实现流量控制.Semaphore提供了一个许可证的概念,可以把这个许可证看作公共汽车车票,只有成功获取车票的人才能够上车,并且车票是有一定数量的,不可能毫无限制的发下去,这样就会导致公交车超载.所以当车票发完的时候(公交车以满载),其他人就只能等下一趟车了.如果中途有人下车,那么他的位置将会空闲出来,因此如果这时其他人想要上车

  • Java并发系列之CyclicBarrier源码分析

    现实生活中我们经常会遇到这样的情景,在进行某个活动前需要等待人全部都齐了才开始.例如吃饭时要等全家人都上座了才动筷子,旅游时要等全部人都到齐了才出发,比赛时要等运动员都上场后才开始.在JUC包中为我们提供了一个同步工具类能够很好的模拟这类场景,它就是CyclicBarrier类.利用CyclicBarrier类可以实现一组线程相互等待,当所有线程都到达某个屏障点后再进行后续的操作.下图演示了这一过程. 在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用await

  • Java并发系列之ConcurrentHashMap源码分析

    我们知道哈希表是一种非常高效的数据结构,设计优良的哈希函数可以使其上的增删改查操作达到O(1)级别.Java为我们提供了一个现成的哈希结构,那就是HashMap类,在前面的文章中我曾经介绍过HashMap类,知道它的所有方法都未进行同步,因此在多线程环境中是不安全的.为此,Java为我们提供了另外一个HashTable类,它对于多线程同步的处理非常简单粗暴,那就是在HashMap的基础上对其所有方法都使用synchronized关键字进行加锁.这种方法虽然简单,但导致了一个问题,那就是在同一时间

随机推荐