前言
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 方法.