为什么线程协作之前必须先获得锁?

Java中,线程协作的wait/notify机制要求在调用前持有对象锁,这是JLS的规定。如果未持有锁直接调用,线程将抛出IllegalMonitorStateException。本文通过分析OpenJDK源码,探讨这一机制的实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么Object.wait()/notify()/notifyAll() 之前必须获得锁? 这是JLS的规定。Wait-notify机制是围绕监控器锁进行的,获得锁是很自然的前提,自身没有拿到锁之前,怎么能够尝试去操作靠锁来调控的线程呢?不过今天偶尔有时间,就看下Sun Hotspot是怎么实现这一机制的。

当我们执行下面的代码时,线程会抛出异常java.lang.IllegalMonitorStateException: current thread not owner。

publicclass WaitNotifyCompilerCode {privateString aString ="Hello World!";
 
	publicstaticvoid main(String[] args){System.out.println("Execute start ....");final WaitNotifyCompilerCode w =new WaitNotifyCompilerCode();
		w.wait1SecAndPrintString();System.out.println("Execute end ....");}
 
	publicvoid wait1SecAndPrintString(){try{this.wait(1000);}catch(InterruptedException e){
			e.printStackTrace();}System.out.println(aString);}
 
}

异常栈的信息如下:

Exception in thread "main" java.lang.IllegalMonitorStateException: current thread not owner
	at java.lang.Object.wait(NativeMethod)
	at com.feihoo.test.waitnotify.WaitNotifyCompilerCode.wait1SecAndPrintString(WaitNotifyCompilerCode.java:35)
	at com.feihoo.test.waitnotify.WaitNotifyCompilerCode.main(WaitNotifyCompilerCode.java:27)

深入查看 OpenJDK的源码,找到 Object.wait() 函数本地代码:

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));assert(obj->is_instance()|| obj->is_array(), "JVM_MonitorWait must apply to an object");
  JavaThreadInObjectWaitState jtiows(thread, ms !=0);if(JvmtiExport::should_post_monitor_wait()){
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);}
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END

重点看倒数第二行,调用的函数如下面的代码:

// NOTE: must use heavy weight monitor to handle wait()void 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(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");}
  ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
  DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
  monitor->wait(millis, true, THREAD);

而上面的代码中最后一行的函数里,在做实际操作之前调用了下面的宏:

// A macro is used below because there may already be a pending// exception which should not abort the execution of the routines// which use this (which is why we don't put this into check_slow and// call it with a CHECK argument).
 
#define CHECK_OWNER()                                                             \
  do {                                                                            \
    if (THREAD != _owner) {                                                       \
      if (THREAD->is_lock_owned((address) _owner)) {                              \
        _owner = THREAD ;  /* Convert from basiclock addr to Thread addr */       \
        _recursions = 0;                                                          \
        OwnerIsThread = 1 ;                                                       \
      } else {                                                                    \
        TEVENT (Throw IMSX) ;                                                     \
        THROW(vmSymbols::java_lang_IllegalMonitorStateException());               \
      }                                                                           \
    }                                                                             \
  } while (false)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值