码迷,mamicode.com
首页 > 其他好文 > 详细

从 JDK 源码角度看 Object

时间:2018-10-10 17:11:39      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:spin   使用   env   ash   tab   同步   object类   outside   jnienv   

ava的Object是所有其他类的父类,从继承的层次来看它就是最顶层根,所以它也是唯一一个没有父类的类。它包含了对象常用的一些方法,比如getClass、hashCode、equals、clone、toString、notify、wait等常用方法。所以其他类继承了Object后就可以不用重复实现这些方法。这些方法大多数是native方法,下面具体分析。

主要的代码如下:

publicclassObject{privatestaticnativevoidregisterNatives();static{ registerNatives(); }publicfinalnativeClass getClass();publicnativeinthashCode();publicbooleanequals(Object obj){return(this== obj); }protectednativeObjectclone()throwsCloneNotSupportedException;publicStringtoString(){returngetClass().getName() +"@"+ Integer.toHexString(hashCode()); }publicfinalnativevoidnotify();publicfinalnativevoidnotifyAll();publicfinalnativevoidwait(longtimeout)throwsInterruptedException;publicfinalvoidwait(longtimeout,intnanos)throwsInterruptedException{if(timeout <0) {thrownewIllegalArgumentException("timeout value is negative"); }if(nanos <0|| nanos >999999) {thrownewIllegalArgumentException("nanosecond timeout value out of range"); }if(nanos >0) { timeout++; } wait(timeout); }publicfinalvoidwait()throwsInterruptedException{ wait(0); }protectedvoidfinalize()throwsThrowable{}}

registerNatives方法

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

JNIEXPORTvoidJNICALLJava_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类型。这个映射其实就可以看成将字符串映射到函数指针。

staticJNINativeMethod 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 JNICALLJava_java_lang_Object_getClass(JNIEnv env, jobjectthis){if(this==NULL) { JNU_ThrowNullPointerException(env,NULL);return0; }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, GetObjectClassentry, 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, GetObjectClassreturn, ret); return ret;JNI_END

hashCode方法

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

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle)) JVMWrapper("JVM_IHashCode");//as implementedinthe classic virtual machine;return0ifobject is NULLreturnhandle == NULL ?0: ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;JVM_END

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

staticinline intptr_t get_next_hash(Thread *Self, oop obj) { intptr_t value =0;if(hashCode ==0) { value = os::random() ; }elseif(hashCode ==1) { intptr_t addrBits = intptr_t(obj) >>3; value = addrBits ^ (addrBits >>5) ^ GVars.stwRandom ; }elseif(hashCode ==2) { value =1;// for sensitivity testing}elseif(hashCode ==3) { value = ++GVars.hcSequence ; }elseif(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) ;returnvalue;}

equals方法

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

clone方法

由本地方法表知道clone方法对应的本地函数为JVM_Clone,clone方法主要实现对象的克隆功能,根据该对象生成一个相同的新对象(我们常见的类的对象的属性如果是原始类型则会克隆值,但如果是对象则会克隆对象的地址)。Java的类要实现克隆则需要实现Cloneable接口,if (!klass->is_cloneable())这里会校验是否有实现该接口。然后判断是否是数组分两种情况分配内存空间,新对象为new_obj,接着对new_obj进行copy及C++层数据结构的设置。最后再转成jobject类型方便转成Java层的Object类型。

JVM_ENTRY(jobject, JVM_Clone(JNIEnv env, jobject handle)) JVMWrapper("JVM_Clone"); Handle obj(THREAD, JNIHandles::resolve_non_null(handle));constKlassHandle klass (THREAD, obj->klass()); JvmtiVMObjectAllocEventCollector oam;if(!klass->is_cloneable()) { ResourceMark rm(THREAD); THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name()); }constint size = obj->size(); oop new_obj =NULL;if(obj->is_javaArray()) {constint 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); }returnJNIHandles::make_local(env, oop(new_obj));JVM_END

toString方法

逻辑是获取class名称加上@再加上十六进制的hashCode。

notify方法

此方法用来唤醒线程,final修饰说明不可重写。与之对应的本地方法为JVM_MonitorNotify,ObjectSynchronizer::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 EntryListif(List==NULL) { iterator->_next = iterator->_prev =NULL; _EntryList = iterator ; }else{List->_prev = iterator ; iterator->_next =List; iterator->_prev =NULL; _EntryList = iterator ; } }elseif(Policy ==1) {// append to EntryListif(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; } }elseif(Policy ==2) {// prepend to cxq// prepend to cxqif(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; } } } }elseif(Policy ==3) {// append to cxqiterator->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‘s not useful. With the// exception of wait() timeouts and interrupts the monitor owner// is the only thread that grabs _WaitSetLock. There‘s almost no contention// on _WaitSetLock so it‘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 源码角度看 Object

标签:spin   使用   env   ash   tab   同步   object类   outside   jnienv   

原文地址:http://blog.51cto.com/13961945/2298362

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!