`
lobin
  • 浏览: 425852 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java lock/unlock实现原理: Unsafe monitorEnter、monitorExit、tryMonitorEnter

 
阅读更多

Java lock/unlock实现原理: Unsafe monitorEnter、monitorExit、tryMonitorEnter,这3个方法都有1个参数,表示要锁定的对象。对应的本机实现分别为Unsafe_MonitorEnter、Unsafe_MonitorExit、Unsafe_TryMonitorEnter。

 

monitorEnter方法定义如下:

 

/** Lock the object.  It must get unlocked via {@link #monitorExit}. */
public native void monitorEnter(Object o);
tryMonitorEnter方法定义如下:

 

 

/**
 * Tries to lock the object.  Returns true or false to indicate
 * whether the lock succeeded.  If it did, the object must be
 * unlocked via {@link #monitorExit}.
 */
public native boolean tryMonitorEnter(Object o);
 

 

monitorExit方法定义如下:

 

/**
 * Unlock the object.  It must have been locked via {@link
 * #monitorEnter}.
 */
public native void monitorExit(Object o);
 

 

Unsafe_MonitorEnter方法实现在hotspot\src\share\vm\prims\unsafe.cpp中,代码如下:

 

UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj))
  UnsafeWrapper("Unsafe_MonitorEnter");
  {
    if (jobj == NULL) {
      THROW(vmSymbols::java_lang_NullPointerException());
    }
    Handle obj(thread, JNIHandles::resolve_non_null(jobj));
    ObjectSynchronizer::jni_enter(obj, CHECK);
  }
UNSAFE_END
以上代码需要将宏展开,从代码上看,
 
void ATTR ObjectMonitor::enter(TRAPS) {
  // The following code is ordered to check the most common cases first
  // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
  Thread * const Self = THREAD ;
  void * cur ;

  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 ;
  }

  if (cur == Self) {
     // TODO-FIXME: check for integer overflow!  BUGID 6557169.
     _recursions ++ ;
     return ;
  }

  if (Self->is_lock_owned ((address)cur)) {
    assert (_recursions == 0, "internal state error");
    _recursions = 1 ;
    // Commute owner from a thread-specific on-stack BasicLockObject address to
    // a full-fledged "Thread *".
    _owner = Self ;
    OwnerIsThread = 1 ;
    return ;
  }

  // We've encountered genuine contention.
  assert (Self->_Stalled == 0, "invariant") ;
  Self->_Stalled = intptr_t(this) ;

  // Try one round of spinning *before* enqueueing Self
  // and before going through the awkward and expensive state
  // transitions.  The following spin is strictly optional ...
  // Note that if we acquire the monitor from an initial spin
  // we forgo posting JVMTI events and firing DTRACE probes.
  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") ;

  // Prevent deflation at STW-time.  See deflate_idle_monitors() and is_busy().
  // Ensure the object-monitor relationship remains stable while there's contention.
  Atomic::inc_ptr(&_count);

  { // Change java thread status to indicate blocked on monitor enter.
    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);

    // TODO-FIXME: change the following for(;;) loop to straight-line code.
    for (;;) {
      jt->set_suspend_equivalent();
      // cleared by handle_special_suspend_equivalent_condition()
      // or java_suspend_self()

      EnterI (THREAD) ;

      if (!ExitSuspendEquivalent(jt)) break ;

      //
      // We have acquired the contended monitor, but while we were
      // waiting another thread suspended us. We don't want to enter
      // the monitor while suspended because that would surprise the
      // thread that suspended us.
      //
          _recursions = 0 ;
      _succ = NULL ;
      exit (Self) ;

      jt->java_suspend_self();
    }
    Self->set_current_pending_monitor(NULL);
  }

  Atomic::dec_ptr(&_count);
  assert (_count >= 0, "invariant") ;
  Self->_Stalled = 0 ;

  // Must either set _recursions = 0 or ASSERT _recursions == 0.
  assert (_recursions == 0     , "invariant") ;
  assert (_owner == Self       , "invariant") ;
  assert (_succ  != Self       , "invariant") ;
  assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;

  // The thread -- now the owner -- is back in vm mode.
  // Report the glorious news via TI,DTrace and jvmstat.
  // The probe effect is non-trivial.  All the reportage occurs
  // while we hold the monitor, increasing the length of the critical
  // section.  Amdahl's parallel speedup law comes vividly into play.
  //
  // Another option might be to aggregate the events (thread local or
  // per-monitor aggregation) and defer reporting until a more opportune
  // time -- such as next time some thread encounters contention but has
  // yet to acquire the lock.  While spinning that thread could
  // spinning we could increment JVMStat counters, etc.

  DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
  if (JvmtiExport::should_post_monitor_contended_entered()) {
    JvmtiExport::post_monitor_contended_entered(jt, this);
  }
  if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
     ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
  }
}
 
Unsafe_TryMonitorEnter方法实现在hotspot\src\share\vm\prims\unsafe.cpp中,代码如下:

 

UNSAFE_ENTRY(jboolean, Unsafe_TryMonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj))
  UnsafeWrapper("Unsafe_TryMonitorEnter");
  {
    if (jobj == NULL) {
      THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE);
    }
    Handle obj(thread, JNIHandles::resolve_non_null(jobj));
    bool res = ObjectSynchronizer::jni_try_enter(obj, CHECK_0);
    return (res ? JNI_TRUE : JNI_FALSE);
  }
UNSAFE_END 
 
bool ObjectMonitor::try_enter(Thread* THREAD) {
  if (THREAD != _owner) {
    if (THREAD->is_lock_owned ((address)_owner)) {
       assert(_recursions == 0, "internal state error");
       _owner = THREAD ;
       _recursions = 1 ;
       OwnerIsThread = 1 ;
       return true;
    }
    if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
      return false;
    }
    return true;
  } else {
    _recursions++;
    return true;
  }
}
 
Unsafe_MonitorExit方法实现在hotspot\src\share\vm\prims\unsafe.cpp中,代码如下:
UNSAFE_ENTRY(void, Unsafe_MonitorExit(JNIEnv *env, jobject unsafe, jobject jobj))
  UnsafeWrapper("Unsafe_MonitorExit");
  {
    if (jobj == NULL) {
      THROW(vmSymbols::java_lang_NullPointerException());
    }
    Handle obj(THREAD, JNIHandles::resolve_non_null(jobj));
    ObjectSynchronizer::jni_exit(obj(), CHECK);
  }
UNSAFE_END
 
分享到:
评论

相关推荐

    JDK8中sun.misc下UnSafe类源代码 UnSafe.java

    在Java编程中,sun.misc.UnSafe类是一个非常特殊的存在。这个类在JDK8中扮演着一个核心的角色,它提供了对Java语言规范中未公开的底层操作的访问。尽管UnSafe类并非设计为公共API的一部分,但它因其强大的功能而被...

    java魔法类:Unsafe应用

    java魔法类:Unsafe应用

    Thumbor的Java客户端Pollexor.zip

    Pollexor 是 Thumbor 图片服务的 JAVA 客户端,兼容 Android 平台。... .toUrl()// Produces: /unsafe/200x100/filters:round_corner(10,255,255,255):watermark(/unsafe/200x100/example.c 标签:Pollexor

    开源项目-lucas-clemente-quic-go.zip

    【开源项目-lucas-clemente-quic-go.zip】是一个基于Go语言实现的QUIC协议服务器端开源项目。QUIC(Quick UDP Internet Connections)是由Google设计并推广的一种低延迟、高性能的网络传输协议,旨在替代传统的TCP...

    CSC编译参数[归类].pdf

    24. **/unsafe**:允许使用不安全的C#代码,如指针操作。 25. **/warn**:设置警告级别,控制编译时警告的显示。 26. **/warnaserror**:将警告提升为错误,使得编译器在遇到警告时停止编译。 27. **/win32icon**...

    csc命令帮助

    - `/unsafe-`: 不允许不安全代码。 **20. @<file>:** 读取命令行参数文件。 ``` csc @buildparams.txt ``` **21. /help:** 显示帮助信息。 ``` csc /help ``` **22. /nologo:** 禁用显示版权信息。 ``` csc /...

    sun.misc.Unsafe源码

    《深入解析Java sun.misc.Unsafe》 ...不过,了解`Unsafe`的工作原理对于提升对Java内存模型和并发编程的理解是非常有益的。在研究高性能、低延迟或特殊场景下的优化时,`Unsafe`可能会成为一种有效的解决方案。

    「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识 准备 Java 面试,首选.zip

    Java 魔法类 Unsafe 详解 Java SPI 机制详解 Java 语法糖详解 集合 知识点/面试题总结 : Java 集合常见知识点&面试题总结(上) (必看 ) Java 集合常见知识点&面试题总结(下) (必看 ) Java 容器使用注意事项总结 ...

    「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识

    Java 魔法类 Unsafe 详解 Java SPI 机制详解 Java 语法糖详解 集合 知识点/面试题总结: Java 集合常见知识点&面试题总结(上) (必看 ) Java 集合常见知识点&面试题总结(下) (必看 ) Java 容器使用注意事项总结 源码...

    「Java学习+面试指南」部分内容大部分是Java程序员所需要掌握的核心知识

    Java序列化详解泛型&通配符详解Java 引用机制详解Java代理模式详解BigDecimal 详细解Java 魔法类 Unsafe 详细解Java SPI 机制详解Java语法糖详解集合知识点/面试题总结:Java集合常见知识点&面试题总结(上)(必看...

    MessageBox3.cs

    // 编译命令:csc /unsafe UnSafeSwap.cs using System; class Program { public static void Main() { int a = 2; int b = 9; Console.WriteLine("交换前:a = {0}, b = {1}", a, b); // 不安全语句 ...

    Java Unsafe类实现原理及测试代码

    虽然`monitorEnter`、`tryMonitorEnter`和`monitorExit`已不建议使用,但`compareAndSwapInt`等CAS方法是无锁编程的关键,广泛应用于`Atomic`系列类中,以提高并发性能。 六、挂起与恢复 `park`和`unpark`方法用于...

    探秘Java并发:Atomic&Unsafe的强大魔法

    本文深入解析Java并发编程中的两个关键类:Atomic和Unsafe。这些类在提高Java并发操作的效率和安全性方面扮演着至关重要的角色。原子操作的核心:原子操作是不可分割的操作单元,确保数据的一致性和完整性。Java通过...

    【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    Java 魔法类 Unsafe 详解 Java SPI 机制详解 Java 语法糖详解 集合 知识点/面试题总结: Java 集合常见知识点&面试题总结(上) (必看 ) Java 集合常见知识点&面试题总结(下) (必看 ) Java 容器使用注意事项总结 源码...

    ugorji-go-codec

    该软件包了解unsafe标记,以允许使用不安全的语义: 解码为结构体时,您需要将字段名称读取为字符串,以便找到映射到其的结构体字段。 使用unsafe将绕过[]byte->string转换的分配和复制开销。 要使用它,必须在...

    免费开源-【Java学习+面试指南】部分内容大部分是Java程序员所需要掌握的核心知识

    Java序列化详解泛型&通配符详解Java 引用机制详解Java代理模式详解BigDecimal 详细解Java 魔法类 Unsafe 详细解Java SPI 机制详解Java语法糖详解集合知识点/面试题总结:Java集合常见知识点&面试题总结(上)(必看...

    Socket通信

    实现Socket通信。 /// /// 网络通讯事件模型委托 /// </summary> public delegate void NetEvent(object sender, NetEventArgs e); /// /// 提供TCP连接服务的服务器类 /// /// 版本: 1.1 /// 替换版本:...

    Hbase详细安装步骤

    <name>hbase.unsafe.stream.capability.enforce</name> <value>false</value> </property> ``` 运行 HBase 1. 运行 ssh localhost 2. 运行 hadoop——start-dfs.sh 3. 运行 hbase——start-hbase.sh 4. 运行 ...

    基于JDK源码解析Java领域中的并发锁之设计与实现.pdf

    在Java并发编程中,理解和掌握并发锁的原理与实现至关重要,因为它们是解决多线程环境下的互斥和同步问题的关键。本文将基于JDK源码解析Java领域中的并发锁,探讨AQS基础同步器、LockSupport、Condition接口、Lock...

    java synchronized关键字原理、自定义一把锁来实现同步等

    ### Java synchronized 关键字原理与自定义锁实现详解 #### 一、Java synchronized 关键字原理 `synchronized` 是 Java 中的关键字之一,用于实现线程间的同步控制,确保共享资源的安全访问。它主要应用于以下两种...

Global site tag (gtag.js) - Google Analytics