同一个对象的wait操作被不同线程调用


对于Object wait操作的发现,同一个对象的wait操作被不同线程调用,synchronized不起作用。

public class SyncAndWait {
    private Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        SyncAndWait sync = new SyncAndWait();

        new Thread(() -> {sync.sync();}).start();

        new Thread(() -> {sync.sync();}).start();

        Thread.sleep(5000);
    }

    public void sync() {
        synchronized (obj) {
            System.out.println("sync");
//            try {
//                obj.wait(5000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

执行上面代码,我们都知道两个sync相隔5s。 而如果去掉注释,sync就是接着输出的。这是为什么呢?

这里我们得要进入wait的native方法找答案了。

Object.c

static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};

jvm.cpp

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

最主要的就是ObjectSynchronizer::wait,参见synchronizer.cpp,首先偏向锁校验,这里需要撤销偏向锁。接下来时间校验,以及释放当前持有的锁,并将线程加入到obj所属的条件队列,而后阻塞

synchronizer.cpp

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

参考资料:Wait-Notify机制

-----------------------------------------------如有错误请指正------------------------------


上篇: 纪念下为知,第888篇 下篇: Netty boss线程 Accept