JDKソースコードの観点から見たオブジェクトのJavaサンプル分析

黄舟
リリース: 2017-07-18 09:46:24
オリジナル
1414 人が閲覧しました

Object はすべてのクラスの親クラスです。つまり、Java のすべてのクラスは Object クラスから直接または間接的に継承します。たとえば、クラス A を何気なく作成すると、明示的には記載されていませんが、デフォルトでオブジェクトを継承します。

の後の 3 つのドット「...」は、不確実な数のパラメーターが受け入れられることを示します。古い書き方は Object args[] ですが、新しいバージョンの Java では ... を使って表現することが推奨されています。たとえば、

public void getSomething(String ...  strings)(){}
ログイン後にコピー

object は Java のすべてのクラスの親クラスです。つまり、すべてのクラスは、自分で作成したものでも、システム内で作成したものでも、オブジェクト クラスを継承します。つまり、すべてのクラスがいつでも置き換えることができます。オブジェクト クラスは、リスコフ置換原則によれば、いつでも親クラスを置き換えることができますが、親クラスが必ずしもそのサブクラスを置き換えるわけではありません。これは実際に Java でよく言われることです。「すべてがオブジェクトである」ということです。 oop 思考におけるポリモーフィズム、継承、カプセル化、抽象化の 4 つの主要な特徴を理解します。


オブジェクト クラスは、データ型ではなく、すべてのクラスの基本クラスです。これについては、jdk ドキュメントを参照してください。すべてのクラスは Object から継承します。

オブジェクト ...オブジェクト この種のパラメータ定義は、メソッドのパラメータが不確実な場合の多態性表現の一種です。つまり、このメソッドは複数のパラメーターを渡すことができますが、パラメーターの数は不確かです。このように、メソッド本体でそれに応じた処理を行う必要があります。 Object は基本クラスであるため、Object...objects 形式のパラメータを使用して、Object から継承されたすべてのオブジェクトをパラメータとして使用できるようにします。この方法が実際に使用されることは比較的まれです。

Object[] obj は、Object 配列で構成されるパラメータ形式です。このメソッドのパラメータは固定されており、Object 配列であることに注意してください。この配列に格納される要素については、Object を継承するすべてのクラスのオブジェクトにすることができます。

これらの基本的なことについては、「Java で考える」を何度か読むことをお勧めします。

getClasshashCodeequalsclonetoStringnotifywait等常用方法。所以其他类继承了Object后就可以不用重复实现这些方法。这些方法大多数是native方法,下面具体分析。

主要的代码如下:

public class Object {
  private static native void registerNatives();
  static {
    registerNatives();
  }
  public final native Class<?> getClass();
  public native int hashCode();
  public boolean equals(Object obj) {
    return (this == obj);
  }
  protected native Object clone() throws CloneNotSupportedException;
  public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
  }

  public final native void notify();

  public final native void notifyAll();

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

  public final void wait(long timeout, int nanos) throws InterruptedException {
    if (timeout < 0) {
      throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
      throw new IllegalArgumentException("nanosecond timeout value out of range");
    }

    if (nanos > 0) {
      timeout++;
    }

    wait(timeout);
  }

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

  protected void finalize() throws Throwable {}
}
ログイン後にコピー

registerNatives方法

由于registerNatives方法被static块修饰,所以在加载Object类时就会执行该方法,对应的本地方法为Java_java_lang_Object_registerNatives,如下,

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
ログイン後にコピー

可以看到它间接调用了JNINativeInterface_结构体的方法,简单可以看成是这样:它干的事大概就是将Java层的方法名和本地函数对应起来,方便执行引擎在执行字节码时根据这些对应关系表来调用C/C++函数,如下面,将这些方法进行注册,执行引擎执行到hashCode方法时就可以通过关系表来查找到JVM的JVM_IHashCode函数,其中()I还可以得知Java层上的类型应该转为int类型。这个映射其实就可以看成将字符串映射到函数指针。

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},
};
ログイン後にコピー

getClass方法

getClass方法也是个本地方法,对应的本地方法为Java_java_lang_Object_getClass,如下:

JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
{
    if (this == NULL) {
        JNU_ThrowNullPointerException(env, NULL);
        return 0;
    } else {
        return (*env)->GetObjectClass(env, this);
    }
}
ログイン後にコピー

所以这里主要就是看GetObjectClass函数了,Java层的Class在C++层与之对应的则是klassOop,所以关于类的元数据和方法信息可以通过它获得。

JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj))
  JNIWrapper("GetObjectClass");
  DTRACE_PROBE2(hotspot_jni, GetObjectClass__entry, env, obj);
  klassOop k = JNIHandles::resolve_non_null(obj)->klass();
  jclass ret =
    (jclass) JNIHandles::make_local(env, Klass::cast(k)->java_mirror());
  DTRACE_PROBE1(hotspot_jni, GetObjectClass__return, ret);
  return ret;
JNI_END
ログイン後にコピー

hashCode方法

由前面registerNatives方法将几个本地方法注册可知,hashCode方法对应的函数为JVM_IHashCode,即

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_IHashCode");
  // as implemented in the classic virtual machine; return 0 if object is NULL
  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END
ログイン後にコピー

对于hashcode生成的逻辑由synchronizer.cppget_next_hash函数决定,实现比较复杂,根据hashcode的不同值有不同的生成策略,最后使用一个hash掩码处理。

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     value = os::random() ;
  } else
  if (hashCode == 1) {
     intptr_t addrBits = intptr_t(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else
  if (hashCode == 2) {
     value = 1 ;            // for sensitivity testing
  } else
  if (hashCode == 3) {
     value = ++GVars.hcSequence ;
  } else
  if (hashCode == 4) {
     value = intptr_t(obj) ;
  } else {
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;
  }

  value &= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ;
  assert (value != markOopDesc::no_hash, "invariant") ;
  TEVENT (hashCode: GENERATE) ;
  return value;
}
ログイン後にコピー

equals方法

这是一个非本地方法,判断逻辑也十分简单,直接==比较。

clone方法

由本地方法表知道clone方法对应的本地函数为JVM_Clone,clone方法主要实现对象的克隆功能,根据该对象生成一个相同的新对象(我们常见的类的对象的属性如果是原始类型则会克隆值,但如果是对象则会克隆对象的地址)。Java的类要实现克隆则需要实现Cloneable接口,if (!klass->is_cloneable()) Java の Object は、継承レベルから見ると、他のすべてのクラスの親クラスであり、したがって唯一のクラスでもあります。親クラスのないクラス。 getClasshashCodeequalsclone など、オブジェクトによって一般的に使用されるいくつかのメソッドが含まれています。 >toString notifywait、およびその他の一般的なメソッド。したがって、他のクラスは Object を継承した後にこれらのメソッドを繰り返し実装する必要がありません。これらのメソッドのほとんどはネイティブ メソッドであり、以下で詳しく分析します。

メインのコードは次のとおりです:

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_Clone");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  const KlassHandle klass (THREAD, obj->klass());
  JvmtiVMObjectAllocEventCollector oam;

  if (!klass->is_cloneable()) {
    ResourceMark rm(THREAD);
    THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
  }

  const int size = obj->size();
  oop new_obj = NULL;
  if (obj->is_javaArray()) {
    const int length = ((arrayOop)obj())->length();
    new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);
  } else {
    new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
  }
  Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj,
                               (size_t)align_object_size(size) / HeapWordsPerLong);
  new_obj->init_mark();

  BarrierSet* bs = Universe::heap()->barrier_set();
  assert(bs->has_write_region_opt(), "Barrier set does not have write_region");
  bs->write_region(MemRegion((HeapWord*)new_obj, size));

  if (klass->has_finalizer()) {
    assert(obj->is_instance(), "should be instanceOop");
    new_obj = instanceKlass::register_finalizer(instanceOop(new_obj), CHECK_NULL);
  }

  return JNIHandles::make_local(env, oop(new_obj));
JVM_END
ログイン後にコピー

registerNatives メソッド

🎜 registerNatives メソッドは静的ブロックによって変更されるため、このメソッドは Object クラスがロードされるときに実行されます。対応するローカル メソッドは Java_java_lang_Object_registerNatives</ です。 code> は、次のように、🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:java;toolbar:false;">JVM_ENTRY(void, JVM_MonitorNotify(JNIEnv* env, jobject handle)) JVMWrapper(&quot;JVM_MonitorNotify&quot;); Handle obj(THREAD, JNIHandles::resolve_non_null(handle)); assert(obj-&gt;is_instance() || obj-&gt;is_array(), &quot;JVM_MonitorNotify must apply to an object&quot;); ObjectSynchronizer::notify(obj, CHECK); JVM_END</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>🎜 <code>JNINativeInterface_ 構造体のメソッドを間接的に呼び出していることがわかります。これは単純に次のように見ることができます。これはおそらく、そのメソッド名と一致することです。実行エンジンを容易にするローカル関数を備えた Java 層 バイトコードを実行する場合、以下に示すように、実行エンジンが hashCode を実行するときに、これらのメソッドが登録されます。 JVM_IHashCode 関数では、()I によって、Java 層の型を int に変換する必要があることもわかります。タイプ。このマッピングは、実際には文字列を関数ポインターにマッピングするものとみなすことができます。 🎜
void ObjectMonitor::notify(TRAPS) {
  CHECK_OWNER();
  if (_WaitSet == NULL) {
     TEVENT (Empty-Notify) ;
     return ;
  }
  DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);

  int Policy = Knob_MoveNotifyee ;

  Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
  ObjectWaiter * iterator = DequeueWaiter() ;
  if (iterator != NULL) {
     TEVENT (Notify1 - Transfer) ;
     guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
     guarantee (iterator->_notified == 0, "invariant") ;
     if (Policy != 4) {
        iterator->TState = ObjectWaiter::TS_ENTER ;
     }
     iterator->_notified = 1 ;

     ObjectWaiter * List = _EntryList ;
     if (List != NULL) {
        assert (List->_prev == NULL, "invariant") ;
        assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
        assert (List != iterator, "invariant") ;
     }

     if (Policy == 0) {       // prepend to EntryList
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
             List->_prev = iterator ;
             iterator->_next = List ;
             iterator->_prev = NULL ;
             _EntryList = iterator ;
        }
     } else
     if (Policy == 1) {      // append to EntryList
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
            // CONSIDER:  finding the tail currently requires a linear-time walk of
            // the EntryList.  We can make tail access constant-time by converting to
            // a CDLL instead of using our current DLL.
            ObjectWaiter * Tail ;
            for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
            assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
            Tail->_next = iterator ;
            iterator->_prev = Tail ;
            iterator->_next = NULL ;
        }
     } else
     if (Policy == 2) {      // prepend to cxq
         // prepend to cxq
         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 ;
                }
            }
         }
     } else
     if (Policy == 3) {      // append to cxq
        iterator->TState = ObjectWaiter::TS_CXQ ;
        for (;;) {
            ObjectWaiter * Tail ;
            Tail = _cxq ;
            if (Tail == NULL) {
                iterator->_next = NULL ;
                if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
                   break ;
                }
            } else {
                while (Tail->_next != NULL) Tail = Tail->_next ;
                Tail->_next = iterator ;
                iterator->_prev = Tail ;
                iterator->_next = NULL ;
                break ;
            }
        }
     } else {
        ParkEvent * ev = iterator->_event ;
        iterator->TState = ObjectWaiter::TS_RUN ;
        OrderAccess::fence() ;
        ev->unpark() ;
     }

     if (Policy < 4) {
       iterator->wait_reenter_begin(this);
     }

     // _WaitSetLock protects the wait queue, not the EntryList.  We could
     // move the add-to-EntryList operation, above, outside the critical section
     // protected by _WaitSetLock.  In practice that&#39;s not useful.  With the
     // exception of  wait() timeouts and interrupts the monitor owner
     // is the only thread that grabs _WaitSetLock.  There&#39;s almost no contention
     // on _WaitSetLock so it&#39;s not profitable to reduce the length of the
     // critical section.
  }

  Thread::SpinRelease (&_WaitSetLock) ;

  if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
     ObjectMonitor::_sync_Notifications->inc() ;
  }
}
ログイン後にコピー
ログイン後にコピー
🎜getClass メソッド🎜🎜getClass メソッドもローカル メソッドです。次のように、対応するローカル メソッドは Java_java_lang_Object_getClass です。 🎜
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
ログイン後にコピー
ログイン後にコピー
🎜 したがって、ここでは主に GetObjectClass について説明します。 function、Java この層のクラスは C++ 層の klassOop に対応するため、クラスに関するメタデータとメソッド情報はそれを通じて取得できます。 🎜rrreee🎜hashCodeメソッド🎜🎜先ほどのregisterNativesメソッドで複数のローカルメソッドを登録していることからわかるように、hashCodeメソッドに対応する関数はJVM_IHashCode、つまり🎜rrreee🎜ハッシュコードによって生成されるロジックです。 synchronizer.cpp get_next_hash 関数によって生成されます。実装はより複雑ですが、ハッシュコードの値に応じて異なる生成戦略が存在します。最後にハッシュマスクが処理に使用されます。 🎜rrreee🎜equalsメソッド🎜🎜これは非ローカルなメソッドであり、判定ロジックも非常にシンプルで直接==比較です。 🎜🎜clone メソッド🎜🎜 ローカル メソッド テーブルから、clone メソッドに対応するローカル関数は JVM_Clone であることがわかります。clone メソッドは主にオブジェクトのクローン作成機能を実装し、同一の新しいオブジェクト ベースを生成します。オブジェクト上で (共通クラスのオブジェクトのプロパティは、プリミティブ型の場合は値を複製しますが、オブジェクトの場合はオブジェクトのアドレスを複製します)。クローン作成を実装するには、Java クラスで Cloneable インターフェイスを実装する必要があります。 if (!klass->is_cloneable()) は、インターフェイスが実装されているかどうかを確認します。次に、それが配列であるかどうかを判断し、新しいオブジェクトが new_obj である場合にメモリ領域を割り当て、次に new_obj の C++ 層データ構造をコピーして設定します。最後に、Java 層の Object 型への変換を容易にするために、jobject 型に変換されます。 🎜rrreee🎜toString メソッド🎜🎜 このロジックは、クラス名と @ に加えて 16 進数の hashCode を取得することです。 🎜

notify方法

此方法用来唤醒线程,final修饰说明不可重写。与之对应的本地方法为JVM_MonitorNotifyObjectSynchronizer::notify最终会调用ObjectMonitor::notify(TRAPS),这个过程是ObjectSynchronizer会尝试当前线程获取free ObjectMonitor对象,不成功则尝试从全局中获取。

JVM_ENTRY(void, JVM_MonitorNotify(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_MonitorNotify");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  assert(obj->is_instance() || obj->is_array(), "JVM_MonitorNotify must apply to an object");
  ObjectSynchronizer::notify(obj, CHECK);
JVM_END
ログイン後にコピー
ログイン後にコピー

ObjectMonitor对象包含一个_WaitSet队列对象,此对象保存着所有处于wait状态的线程,用ObjectWaiter对象表示。notify要做的事是先获取_WaitSet队列锁,再取出_WaitSet队列中第一个ObjectWaiter对象,再根据不同策略处理该对象,比如把它加入到_EntryList队列中。然后再释放_WaitSet队列锁。它并没有释放synchronized对应的锁,所以锁只能等到synchronized同步块结束时才释放。

void ObjectMonitor::notify(TRAPS) {
  CHECK_OWNER();
  if (_WaitSet == NULL) {
     TEVENT (Empty-Notify) ;
     return ;
  }
  DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);

  int Policy = Knob_MoveNotifyee ;

  Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
  ObjectWaiter * iterator = DequeueWaiter() ;
  if (iterator != NULL) {
     TEVENT (Notify1 - Transfer) ;
     guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
     guarantee (iterator->_notified == 0, "invariant") ;
     if (Policy != 4) {
        iterator->TState = ObjectWaiter::TS_ENTER ;
     }
     iterator->_notified = 1 ;

     ObjectWaiter * List = _EntryList ;
     if (List != NULL) {
        assert (List->_prev == NULL, "invariant") ;
        assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
        assert (List != iterator, "invariant") ;
     }

     if (Policy == 0) {       // prepend to EntryList
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
             List->_prev = iterator ;
             iterator->_next = List ;
             iterator->_prev = NULL ;
             _EntryList = iterator ;
        }
     } else
     if (Policy == 1) {      // append to EntryList
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
            // CONSIDER:  finding the tail currently requires a linear-time walk of
            // the EntryList.  We can make tail access constant-time by converting to
            // a CDLL instead of using our current DLL.
            ObjectWaiter * Tail ;
            for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
            assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
            Tail->_next = iterator ;
            iterator->_prev = Tail ;
            iterator->_next = NULL ;
        }
     } else
     if (Policy == 2) {      // prepend to cxq
         // prepend to cxq
         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 ;
                }
            }
         }
     } else
     if (Policy == 3) {      // append to cxq
        iterator->TState = ObjectWaiter::TS_CXQ ;
        for (;;) {
            ObjectWaiter * Tail ;
            Tail = _cxq ;
            if (Tail == NULL) {
                iterator->_next = NULL ;
                if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
                   break ;
                }
            } else {
                while (Tail->_next != NULL) Tail = Tail->_next ;
                Tail->_next = iterator ;
                iterator->_prev = Tail ;
                iterator->_next = NULL ;
                break ;
            }
        }
     } else {
        ParkEvent * ev = iterator->_event ;
        iterator->TState = ObjectWaiter::TS_RUN ;
        OrderAccess::fence() ;
        ev->unpark() ;
     }

     if (Policy < 4) {
       iterator->wait_reenter_begin(this);
     }

     // _WaitSetLock protects the wait queue, not the EntryList.  We could
     // move the add-to-EntryList operation, above, outside the critical section
     // protected by _WaitSetLock.  In practice that&#39;s not useful.  With the
     // exception of  wait() timeouts and interrupts the monitor owner
     // is the only thread that grabs _WaitSetLock.  There&#39;s almost no contention
     // on _WaitSetLock so it&#39;s not profitable to reduce the length of the
     // critical section.
  }

  Thread::SpinRelease (&_WaitSetLock) ;

  if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
     ObjectMonitor::_sync_Notifications->inc() ;
  }
}
ログイン後にコピー
ログイン後にコピー

notifyAll方法

与notify方法类似,只是在取_WaitSet队列时不是取第一个而是取所有。

wait方法

wait方法是让线程等待,它对应的本地方法是JVM_MonitorWait,间接调用了ObjectSynchronizer::wait,与notify对应,它也是对应调用ObjectMonitor对象的wait方法。该方法较长,这里不贴出来了,大概就是创建一个ObjectWaiter对象,接着获取_WaitSet队列锁将ObjectWaiter对象添加到该队列中,再释放队列锁。另外,它还会释放synchronized对应的锁,所以锁没有等到synchronized同步块结束时才释放。

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
ログイン後にコピー
ログイン後にコピー

finalize方法

这个方法用于当对象被回收时调用,这个由JVM支持,Object的finalize方法默认是什么都没有做,如果子类需要在对象被回收时执行一些逻辑处理,则可以重写finalize方法。

以上がJDKソースコードの観点から見たオブジェクトのJavaサンプル分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!