欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法

這篇文章主要介紹“如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法”,在日常操作中,相信很多人在如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

創(chuàng)新互聯(lián)專(zhuān)注于網(wǎng)站建設(shè),為客戶提供成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)開(kāi)發(fā)服務(wù),多年建網(wǎng)站服務(wù)經(jīng)驗(yàn),各類(lèi)網(wǎng)站都可以開(kāi)發(fā),品牌網(wǎng)站制作,公司官網(wǎng),公司展示網(wǎng)站,網(wǎng)站設(shè)計(jì),建網(wǎng)站費(fèi)用,建網(wǎng)站多少錢(qián),價(jià)格優(yōu)惠,收費(fèi)合理。

一個(gè)不起眼的小問(wèn)題

上周的工作中我向一個(gè)類(lèi)提交了一個(gè)微不足道的變化,實(shí)現(xiàn)toString()方法用來(lái)讓日志更有用。令我驚訝的是,變化導(dǎo)致約5%的覆蓋率下降。我知道所有新代碼都被現(xiàn)有的單元測(cè)試覆蓋,但是覆蓋率下降了,所以哪里出了問(wèn)題?
對(duì)比之前的覆蓋范圍報(bào)告,一個(gè)敏銳的同事發(fā)現(xiàn),在代碼之前單元測(cè)試覆蓋了HashCode()的實(shí)現(xiàn),但改動(dòng)之后就沒(méi)有覆蓋。當(dāng)然,這是對(duì)的:默認(rèn)的ToString()調(diào)用hashcode(),修改后的沒(méi)有。

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

重寫(xiě)了toString之后,我們自定義的hashCode不再被調(diào)用,所以覆蓋率下降了。所有人都知道默認(rèn)的toString的實(shí)現(xiàn)原理,但是...

默認(rèn)的hashCode方法怎么實(shí)現(xiàn)的?

默認(rèn)的hashCode()返回的是唯一hash碼(identity hash code),注意這個(gè)和重寫(xiě)hashCode返回的hash碼不是一個(gè)東西,如果某個(gè)類(lèi)我們重寫(xiě)了hashCode方法,我們還可以使用System.identityHashCode(o)來(lái)獲取它的唯一hash碼(感覺(jué)這個(gè)就是對(duì)象的身份證號(hào))。
大家普遍認(rèn)為唯一hash碼使用的是對(duì)象內(nèi)存地址的對(duì)應(yīng)的整數(shù)(內(nèi)存整理對(duì)象移動(dòng)了咋辦?),不過(guò)java api文檔是這么說(shuō)的:

... is typically implemented by converting the internal address of the object into an integer, 
but this implementation technique is not required by the Java? programming language.
典型的實(shí)現(xiàn)方式是把對(duì)象的內(nèi)存地址轉(zhuǎn)為一個(gè)整數(shù),但是這種實(shí)現(xiàn)技術(shù)并不是java平臺(tái)必需的

鑒于JVM將重新定位對(duì)象(例如在垃圾收集期間由于晉升或壓縮),在我們計(jì)算對(duì)象的身份哈希碼之后,我們必須保留它。

默認(rèn)的hashCode實(shí)現(xiàn)

對(duì)于默認(rèn)的hashCode方法,不同的JVM可能實(shí)現(xiàn)的方式不一樣,本文只看openJDK的源碼,hashCode是native方法,入口如下:src/share/vm/prims/jvm.hsrc/share/vm/prims/jvm.cpp

508 JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
509   JVMWrapper("JVM_IHashCode");
510   // as implemented in the classic virtual machine; return 0 if object is NULL
511   return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
512 JVM_END

然后是ObjectSynchronizer::FastHashCode()文件是src/share/vm/runtime/synchronizer.cpp 人們可能天真的以為方法像下面這么簡(jiǎn)單:

if (obj.hash() == 0) {
    obj.set_hash(generate_new_hash());
}
return obj.hash();

但實(shí)際上有幾百行...看文件名也大概知道此處涉及到同步,也就是synchronized的實(shí)現(xiàn),是的,就是對(duì)象內(nèi)置鎖。這個(gè)隨后再討論,先看看如何生成唯一hash碼

static inline intptr_t get_next_hash(Thread* self, oop obj) {
  intptr_t value = 0;
  if (hashCode == 0) {
    // This form uses global Park-Miller RNG.
    // On MP system we'll have lots of RW access to a global, so the
    // mechanism induces lots of coherency traffic.
    value = os::random();
  } else if (hashCode == 1) {
    // This variation has the property of being stable (idempotent)
    // between STW operations.  This can be useful in some of the 1-0
    // synchronization schemes.
    intptr_t addr_bits = cast_from_oop<intptr_t>(obj) >> 3;
    value = addr_bits ^ (addr_bits >> 5) ^ GVars.stw_random;
  } else if (hashCode == 2) {
    value = 1;            // for sensitivity testing
  } else if (hashCode == 3) {
    value = ++GVars.hc_sequence;
  } else if (hashCode == 4) {
    value = cast_from_oop<intptr_t>(obj);
  } else {
    // Marsaglia's xor-shift scheme with thread-specific state
    // This is probably the best overall implementation -- we'll
    // likely make this the default in future releases.
    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 &= markWord::hash_mask;
  if (value == 0) value = 0xBAD;
  assert(value != markWord::no_hash, "invariant");
  return value;
}
0. A randomly generated number.隨機(jī)數(shù)
1. A function of memory address of the object.內(nèi)存地址函數(shù)
2. A hardcoded 1 (used for sensitivity testing.)硬編碼為數(shù)字1
3. A sequence.自增序列
4. The memory address of the object, cast to int.內(nèi)存地址強(qiáng)轉(zhuǎn)為int
5. Thread state combined with xorshift (https://en.wikipedia.org/wiki/Xorshift)線程狀態(tài)聯(lián)合x(chóng)orshift

根據(jù)src/share/vm/runtime/globals.hpp中,生產(chǎn)環(huán)境是5,也就是xorshift,應(yīng)該也是一個(gè)隨機(jī)數(shù)方案

1127   product(intx, hashCode, 5,                                                \
1128           "(Unstable) select hashCode generation algorithm")                \

openjdk8和9使用的是5,openjdk7和6使用的是第一種方案(也就是隨機(jī)數(shù)方案)。

對(duì)象頭與同步

在openjdk中,mark word的描述如下:細(xì)節(jié)看這里

30 // The markOop describes the header of an object.
31 //
32 // Note that the mark is not a real oop but just a word.
33 // It is placed in the oop hierarchy for historical reasons.
34 //
35 // Bit-format of an object header (most significant first, big endian layout below):
36 //
37 //  32 bits:
38 //  --------
39 //             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
40 //             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
41 //             size:32 ------------------------------------------>| (CMS free block)
42 //             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
43 //
44 //  64 bits:
45 //  --------
46 //  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
47 //  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
48 //  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
49 //  size:64 ----------------------------------------------------->| (CMS free block)
50 //
51 //  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
52 //  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
53 //  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
54 //  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)

mark word格式在32和64位略有不同。后者有兩個(gè)變體,具體取決于是否啟用了壓縮對(duì)象指針。默認(rèn)情況下,Oracle和OpenJDK 8都執(zhí)行。 如果對(duì)象處于偏向鎖定狀態(tài),那么有23bit存儲(chǔ)的是偏向線程的指針,那么從哪里取唯一hash碼呢?

偏向鎖

對(duì)象的偏向狀態(tài)是偏向鎖導(dǎo)致的。從hotspot6開(kāi)始嘗試減少給一個(gè)對(duì)象加鎖的成本。這些操作很昂貴,因?yàn)樗鼈兊膶?shí)現(xiàn)通常依賴于原子CPU指令(CAS),以便在不同線程上安全地處理對(duì)象上的鎖定/解鎖請(qǐng)求。但是根據(jù)分析,在大多數(shù)應(yīng)用中,大部分的對(duì)象只會(huì)被一個(gè)線程鎖定,所以上述原子指令的執(zhí)行是一種浪費(fèi)(cas指令已經(jīng)很快了,比上下文切換快多了,也是一種浪費(fèi)。。。),為了避免這種浪費(fèi),有偏向鎖定的JVM允許線程讓對(duì)象偏向自己。如果一個(gè)對(duì)象是偏心的,那個(gè)幸運(yùn)的線程加鎖和解鎖連cas指令都不需要執(zhí)行,只有沒(méi)有多個(gè)線程爭(zhēng)取同一個(gè)對(duì)象,偏向鎖的性能會(huì)很好。 繼續(xù)看FastHashCode:

601 intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
602   if (UseBiasedLocking) {
610     if (obj->mark()->has_bias_pattern()) {
          ...
617       BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
          ...
619       assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
620     }
621   }

生成唯一hash碼時(shí),會(huì)撤銷(xiāo)已存在的偏向,并且會(huì)禁用此對(duì)象的偏向能力(false意味著不要嘗試重偏向),上述代碼幾行之后,這個(gè)確實(shí)是不變的:

637   // object should remain ineligible for biased locking
638   assert (!mark->has_bias_pattern(), "invariant") ;

這意味著請(qǐng)求一個(gè)對(duì)象的唯一hash碼會(huì)禁用這個(gè)對(duì)象的偏向鎖,嘗試鎖定此對(duì)象需要使用昂貴的原子指令,即使只有一個(gè)線程請(qǐng)求鎖。

為什么偏向鎖和唯一hash碼有沖突?

要回答這個(gè)問(wèn)題,我們必須了解哪些是標(biāo)記字的可能位置,具體取決于對(duì)象的鎖定狀態(tài)。從HotSpot Wiki的示例圖中有如下轉(zhuǎn)換: 如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法 

到此,關(guān)于“如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

新聞名稱(chēng):如何實(shí)現(xiàn)譯文jdk默認(rèn)hashCode方法
當(dāng)前鏈接:http://chinadenli.net/article32/ghocsc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站網(wǎng)站營(yíng)銷(xiāo)、品牌網(wǎng)站設(shè)計(jì)搜索引擎優(yōu)化網(wǎng)站導(dǎo)航、網(wǎng)頁(yè)設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷(xiāo)型網(wǎng)站建設(shè)