Object.java类中notify调用的是share/vm/prims/jvm.cpp中的JVM_MonitorNotify。
void JVM_MonitorNotify(JNIEnv* env, jobject handle)
{
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
ObjectSynchronizer::notify(obj, CHECK);
}
看看ObjectSynchronizer::notify方法
void ObjectSynchronizer::notify(Handle obj, TRAPS)
{
ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
}
上面的inflate获得一个ObjectMonitor,看看它的具体实现
void ObjectMonitor::notify(TRAPS)
{
if (_WaitSet == NULL) { //没有等待的线程,直接返回
return ;
}
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ; //进入同步区域
ObjectWaiter * iterator = DequeueWaiter() ; //获得一个等待对象
if (iterator != NULL) {
ObjectWaiter * List = _EntryList ; //唤醒队列
//将唤醒的任务加入队列
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
}
}
iterator->wait_reenter_begin(this);
Thread::SpinRelease (&_WaitSetLock) ; //离开同步区域
...........
}
在上面的代码中,只看到了将当前的线程加入唤醒队列的操作,但在wait方法中执行了park()操作,那是执行操作系统的等待方法。上面的步骤显然不能直接唤醒线程运行,那这线程是如何真正运行的呢?
我们知道wait和notify操作是在一个同步块内执行的,如果不在同步块内,会报IllegalMonitorStateException(非法监视器状态违例),真正唤醒的动作是在离开同步块时候,也就是monitorexit操作。
好,我们再看看monitorexit的执行代码,看看是否正确,看看InterpreterRuntime::monitorexit代码
void InterpreterRuntime::monitorexit(JavaThread* thread, BasicObjectLock* elem)
{
Handle h_obj(thread, elem->obj());
ObjectSynchronizer::slow_exit(h_obj(), elem->lock(), thread);
}
跟踪进去,调用的是
void ObjectMonitor::exit
{
...........
w = _EntryList ;
if (w != NULL) {
ExitEpilog (Self, w) ;
return ;
}
}
void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
ParkEvent * Trigger = Wakee->_event ;
.............
Trigger->unpark() ; //通过操作系统提供的方法,真正唤醒线程
}
在上面可以证实是在监视器退去时候真正唤醒线程,同时也就明白了wait和notify 必须在synchronized块里面调用的原因,再回顾上篇wait代码中,也就理解了wait方法内必须执行退出监视器的原因。