资讯专栏INFORMATION COLUMN

OpenJDK9 Hotspot : Object wait/notify 方法浅析

fancyLuo / 2876人阅读

摘要:前言方法是早期提供的一种基于的线程同步方法,本文先介绍相关的数据结构类,然后从方法的内部实现入手,简单分析相关的原理和实现类用于实现的定待和唤醒,不同平台操作系统平台对应的定义在文件类的分配和释放使用了对象缓存,静态字段用于缓存当前

前言

Object wait/notify 方法是早期 JVM 提供的一种基于 Object Monitor 的线程同步方法,本文先介绍相关的数据结构(类),然后从 wait/notify 方法的内部实现入手,简单分析 Object Monitor 相关的原理和实现

Park

Per-thread blocking support for JSR166. Basically, park acts like wait, uppark like notify

Park 类用于实现 JavaThread 的定待(park/wait)和唤醒(unpark/notify),不同平台(操作系统)

PlatformParker

linux 平台对应的 PlatformParker 定义在 hotspot/src/os/linux/vm/os_linux.hpp 文件

class PlatformParker : public CHeapObj {
 protected:
  enum {
    REL_INDEX = 0,
    ABS_INDEX = 1
  };
  int _cur_index;  // which cond is in use: -1, 0, 1
  pthread_mutex_t _mutex[1];
  pthread_cond_t  _cond[2]; // one for relative times and one for abs.

 public:       // TODO-FIXME: make dtor private
  ~PlatformParker() { guarantee(0, "invariant"); }

 public:
  PlatformParker() {
    int status;
    status = pthread_cond_init(&_cond[REL_INDEX], os::Linux::condAttr());
    assert_status(status == 0, status, "cond_init rel");
    status = pthread_cond_init(&_cond[ABS_INDEX], NULL);
    assert_status(status == 0, status, "cond_init abs");
    status = pthread_mutex_init(_mutex, NULL);
    assert_status(status == 0, status, "mutex_init");
    _cur_index = -1; // mark as unused
  }
};
allocate & release

Parker 类的分配和释放使用了对象缓存,静态字段 FreeList 用于缓存当前所有可用的 Parker,ListLock 用于实现对 FreeList 锁,静态方法 Allocate 和 Release 用于分配和释放 Parker

class Parker {
    ...
public:
    ...
    static Parker *Allocate(JavaThread *t);
    static void Release(Parker *e);
private:
    static Parker *volatile FreeList;
    static volatile int ListLock;
}

Allocate 方法首先尝试从 FreeList 中获取 Parker,在此之前要先获取 ListLock;如果分配失败则尝试 new 一个新的 parker,最后设置 Parker 的 AssociatedWith 字段将 Parker 和 JavaThread 关联

Parker * Parker::Allocate (JavaThread * t) {
  guarantee (t != NULL, "invariant") ;
  Parker * p ;

  // Start by trying to recycle an existing but unassociated
  // Parker from the global free list.
  // 8028280: using concurrent free list without memory management can leak
  // pretty badly it turns out.
  Thread::SpinAcquire(&ListLock, "ParkerFreeListAllocate");
  {
    p = FreeList;
    if (p != NULL) {
      FreeList = p->FreeNext;
    }
  }
  Thread::SpinRelease(&ListLock);

  if (p != NULL) {
    guarantee (p->AssociatedWith == NULL, "invariant") ;
  } else {
    // Do this the hard way -- materialize a new Parker..
    p = new Parker() ;
  }
  p->AssociatedWith = t ;          // Associate p with t
  p->FreeNext       = NULL ;
  return p ;
}
park unpark ObjectMonitor ObjectSynchronizer wait

Object 类中的很多方法都是 native 方法,wait 也不例外

public final void wait() throws InterruptedException {
    wait(0);
}

public final native void wait(long timeout) throws InterruptedException;

wait 方法对应的 native 函数为 JVM_MonitorWait

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);

    // The current thread already owns the monitor and it has not yet
    // been added to the wait queue so the current thread cannot be
    // made the successor. This means that the JVMTI_EVENT_MONITOR_WAIT
    // event handler cannot accidentally consume an unpark() meant for
    // the ParkEvent associated with this ObjectMonitor.
  }
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END

它首先调用 JNIHandles::resolve_non_null 函数将 jobject 类型的 handle 转化为 oop(关于 oop 和 Handle 概念可以参考之前的系列文章),然后调用 ObjectSynchronizer 类的静态方法 wait,这里出现了第一个和 Object Monitor 相关的类 ObjectSynchronizer,先做个标记,接着往下看

int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
  if (UseBiasedLocking) {
    BiasedLocking::revoke_and_rebias(obj, false, THREAD);
    assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
  }
  if (millis < 0) {
    TEVENT(wait - throw IAX);
    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
        "timeout value is negative");
  }
  ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD,
                                                       obj(),
                                                       inflate_cause_wait);

  DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
  monitor->wait(millis, true, THREAD);

  // This dummy call is in place to get around dtrace bug 6254741.  Once
  // that"s fixed we can uncomment the following line, remove the call
  // and change this function back into a "void" func.
  // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
  return dtrace_waited_probe(monitor, obj, THREAD);
}

这里出现了第二个类 ObjectMonitor(主角),通过 ObjectSynchronizer::inflate 方法获取对象的 ObjectMonitor 后调用 monitor 的 wait 方法.

总结

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66728.html

相关文章

  • 线程间的同步与通信(3)——浅析synchronized的实现原理

    摘要:由此可见,自旋锁和各有优劣,他们分别适用于竞争不多和竞争激烈的场景中。每一个试图进入同步代码块的线程都会被封装成对象,它们或在对象的中,或在中,等待成为对象的成为的对象即获取了监视器锁。 前言 系列文章目录 前面两篇文章我们介绍了synchronized同步代码块以及wait和notify机制,大致知道了这些关键字和方法是干什么的,以及怎么用。 但是,知其然,并不知其所以然。 例如...

    keithxiaoy 评论0 收藏0
  • OpenJDK9 Hotspot : synchronized 浅析

    摘要:前言网上各路大神总结过各种关于内部实现,看别人的文章总觉得不过瘾,所以有了这篇文章,尝试再扒一次的底裤数据结构在分析源代码之前需要了解相关概念,比如等,参考网络上各种解说或者之前系列文章,这里重点介绍一下,,每个在内部都有一个的对象与之对应 前言 网上各路大神总结过各种关于 hotspot jvm synchronized 内部实现,看别人的文章总觉得不过瘾,所以有了这篇文章,尝试再扒...

    Amio 评论0 收藏0
  • OpenJDK9 Hotspot:Zero 解释器 初探

    摘要:准备工作假设源代码目录为编译时启用了解释器参考编译和调试调用栈先在函数参考虚拟机入口中设断点,然后在的方法中设置断点通过宏获取当前,然后创建第个栈帧,然后进入解释执行字节码 准备工作 假设 openjdk 源代码目录为 jdk9dev 编译 openjdk 时启用了 zero 解释器(参考 OpenJDK9 Hotspot Mac OSX 编译和调试) 调用栈 先在 JavaMai...

    zhangqh 评论0 收藏0
  • OpenJDK9 Hotspot Mac OSX 编译和调试

    摘要:占用率太高,还出各种奇怪问题,转投调试安装下载源代码漫长等待,中间无数次中断安装安装可选如果要使用解释器,需要安装设置调试级别,设成可以提供更多的调试信息设置路径 Intellij CLion CPU 占用率太高,还出各种奇怪问题,转投 Xcode 调试 hotspot 安装 hg # brew install hg 下载 open jdk 9 源代码 # hg clone http...

    zhichangterry 评论0 收藏0
  • OpenJDK9 Hotspot 虚拟机内部对象内存管理

    摘要:前言语言可以精确控制对象内存分配,出于性能考虑框架系统程序基本都会自己造轮子开发各种内存管理模块也不例外,它通过和方法的访问级别以及重载和方法来管理虚拟机内部对象的内存内存管理相关的基类定义了几个基类来作为大部分对象的基类顾名思义,它们只能 前言 C++ 语言可以精确控制对象内存分配,出于性能考虑 C++ 框架 or 系统程序基本都会自己 造轮子 开发各种内存管理模块. hotspot...

    W_BinaryTree 评论0 收藏0

发表评论

0条评论

fancyLuo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<