摘要:前置知識類的生命周期場景設(shè)計(jì)和推測情況在類中的初始化中實(shí)例化在類的初始化中實(shí)例化類設(shè)計(jì)類靜態(tài)變量靜態(tài)變量之后在靜態(tài)初始化塊里賦值為實(shí)例變量之后再初始化塊中賦值為構(gòu)造函數(shù)類靜態(tài)變量靜態(tài)變量之后在靜態(tài)初始化塊里賦值為實(shí)例變量之后再初始化塊中賦值
前置知識: 類的生命周期
場景設(shè)計(jì)和推測
情況:
在類A中的初始化中實(shí)例化B
在類B的初始化中實(shí)例化A
類設(shè)計(jì)
A類:
靜態(tài)變量a=new B();靜態(tài)變量a1=1(之后在靜態(tài)初始化塊里賦值為2);
實(shí)例變量a2=11(之后再初始化塊中賦值為12);
構(gòu)造函數(shù);
B類:
靜態(tài)變量b=new A();靜態(tài)變量b1=3(之后在靜態(tài)初始化塊里賦值為4);
實(shí)例變量b2=21(之后再初始化塊中賦值為22);
構(gòu)造函數(shù);
猜想執(zhí)行結(jié)果: 由于類初始化之后類實(shí)例化,所以A類初始化需要B實(shí)例化,B實(shí)例化又需要A初始化,造成循環(huán)依賴,最終結(jié)果為死鎖
打點(diǎn)位置:
類加載結(jié)束點(diǎn)(text: Loaded Main2 from file)
類初始化開始點(diǎn)/結(jié)束點(diǎn)(text: Class A2 init)
實(shí)例初始化開始點(diǎn)/結(jié)束點(diǎn)(text: Instance A2 init)
構(gòu)造函數(shù)結(jié)束點(diǎn)(text: Instance A2 new)
場景代碼class A2 { static { System.out.println("Class A2 init start"); } static B2 a = new B2(); static int a1 = 1; { System.out.println("Instance A2 init start. a=" + a + " a1=" + a1 + " a.b2=" + (a == null ? "NPE" : a.b2) + " b=" + B2.b + " b1=" + B2.b1 + " b.a2=" + (B2.b == null ? "NPE" : B2.b.a2)); } public int a2 = 11; static { a1 = 2; System.out.println("Class A2 init end. a=" + a + " a1=" + a1 + " a.b2=" + (a == null ? "NPE" : a.b2) + " b=" + B2.b + " b1=" + B2.b1 + " b.a2=" + (B2.b == null ? "NPE" : B2.b.a2)); } { a2 = 12; System.out.println("Instance A2 init end. a=" + a + " a1=" + a1 + " a.b2=" + (a == null ? "NPE" : a.b2) + " b=" + B2.b + " b1=" + B2.b1 + " b.a2=" + (B2.b == null ? "NPE" : B2.b.a2)); } public A2() { System.out.println("Instance A2 new. a=" + a + " a1=" + a1 + " a.b2=" + (a == null ? "NPE" : a.b2) + " b=" + B2.b + " b1=" + B2.b1 + " b.a2=" + (B2.b == null ? "NPE" : B2.b.a2)); } } class B2 { static { System.out.println("Class B2 init start"); } static A2 b = new A2(); static int b1 = 3; { System.out.println("Instance B2 init start. b=" + b + " b1=" + b1 + " b.a2=" + (b == null ? "NPE" : b.a2) + " a=" + A2.a + " a1=" + A2.a1 + " a.b2=" + (A2.a == null ? "NPE" : A2.a.b2)); } public int b2 = 21; static { b1 = 4; System.out.println("Class B2 init end. b=" + b + " b1=" + b1 + " b.a2=" + (b == null ? "NPE" : b.a2) + " a=" + A2.a + " a1=" + A2.a1 + " a.b2=" + (A2.a == null ? "NPE" : A2.a.b2)); } { b2 = 22; System.out.println("Instance B2 init end. b=" + b + " b1=" + b1 + " b.a2=" + (b == null ? "NPE" : b.a2) + " a=" + A2.a + " a1=" + A2.a1 + " a.b2=" + (A2.a == null ? "NPE" : A2.a.b2)); } public B2() { System.out.println("Instance B2 new. b=" + b + " b1=" + b1 + " b.a2=" + (b == null ? "NPE" : b.a2) + " a=" + A2.a + " a1=" + A2.a1 + " a.b2=" + (A2.a == null ? "NPE" : A2.a.b2)); } } class Main2 { static public void main(String... args) { System.out.println("A2 a=" + A2.a); System.out.println("A2 a1=" + A2.a1); System.out.println("A2 a2=" + B2.b.a2); System.out.println("B2 b=" + B2.b); System.out.println("B2 b1=" + B2.b1); System.out.println("B2 b2=" + A2.a.b2); } }執(zhí)行結(jié)果分析
程序輸出結(jié)果:
1. [Loaded Main2 from file:/Users/jiadongy/JVM_Learning_Sample/out/production/JVM_Learning_Sample/] 2. [Loaded A2 from file:/Users/jiadongy/JVM_Learning_Sample/out/production/JVM_Learning_Sample/] 3. Class A2 init start 4. [Loaded B2 from file:/Users/jiadongy/JVM_Learning_Sample/out/production/JVM_Learning_Sample/] 5. Class B2 init start 6. Instance A2 init start. a=null a1=0 a.b2=NPE b=null b1=0 b.a2=NPE 7. Instance A2 init end. a=null a1=0 a.b2=NPE b=null b1=0 b.a2=NPE 8. Instance A2 new. a=null a1=0 a.b2=NPE b=null b1=0 b.a2=NPE 9. Class B2 init end. b=A2@61bbe9ba b1=4 b.a2=12 a=null a1=0 a.b2=NPE 10. Instance B2 init start. b=A2@61bbe9ba b1=4 b.a2=12 a=null a1=0 a.b2=NPE 11. Instance B2 init end. b=A2@61bbe9ba b1=4 b.a2=12 a=null a1=0 a.b2=NPE 12. Instance B2 new. b=A2@61bbe9ba b1=4 b.a2=12 a=null a1=0 a.b2=NPE 13. Class A2 init end. a=B2@610455d6 a1=2 a.b2=22 b=A2@61bbe9ba b1=4 b.a2=12 14. A2 a=B2@610455d6 15. A2 a1=2 16. A2 a2=12 17. B2 b=A2@61bbe9ba 18. B2 b1=4 19. B2 b2=22
把它轉(zhuǎn)化為下面的表格,更加清晰地描述A/B各個階段執(zhí)行的過程:
A | B |
---|---|
A類加載完成 | |
A類初始化 - 開始 | |
B類加載完成 | |
B類初始化 - 開始 | |
A類實(shí)例初始化 - 開始 | |
A類實(shí)例初始化 - 結(jié)束 | |
A類實(shí)例構(gòu)造函數(shù)執(zhí)行完成 | |
B類初始化 - 結(jié)束 | |
B類實(shí)例初始化 - 開始 | |
B類實(shí)例初始化 - 結(jié)束 | |
B類實(shí)例構(gòu)造函數(shù)執(zhí)行完成 | |
A類初始化 - 結(jié)束 |
可以看到在A類初始化的過程中,A類被實(shí)例化了(并且該階段正常結(jié)束了),也就是說類的初始化階段并不是原子的/排他的.
如在本例中,A類實(shí)例化階段的結(jié)束早于其類初始化階段,A類實(shí)例化完成時,A類的靜態(tài)變量還未被初始化.
Reference.1中已經(jīng)描述了這種情況:
總結(jié)_加載/驗(yàn)證/準(zhǔn)備/初始化和卸載這5個階段的順序是確定的_,類的加載過程必須按照這種順序按部就班的開始...注意,這里筆者寫的是按部就班的"開始",而不是按部就班的"進(jìn)行"或"完成",強(qiáng)調(diào)這點(diǎn)是因?yàn)檫@些階段通都是相互交叉混合式進(jìn)行的,通常會在一個階段執(zhí)行的過程中調(diào)用/激活另外一個階段
<<深入理解Java虛擬機(jī)>>P210
類的循環(huán)初始化不會引起死鎖
5個階段的開始是有順序的,結(jié)束則不一定
階段不是排他的/臨界的
循環(huán)初始化可能引起意料之外的情況,盡量避免
eg.類在初始化過程中修改另一個類的變量,導(dǎo)致另一個類得到了意料之外的初始值
Reference深入理解Java虛擬機(jī)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67280.html
摘要:可能會持有相同的值對象但鍵對象必須是唯一的。當(dāng)有新任務(wù)到達(dá)時,線程池沒有線程則創(chuàng)建線程處理,處理完成后該線程緩存秒,過期后回收,線程過期前有新任務(wù)到達(dá)時,則使用緩存的線程來處理。解決死鎖問題的三種方法預(yù)防死鎖檢測死鎖及避免死鎖。 最近辭職準(zhǔn)備面試,順便整理一下面試題分享給大家,如有錯誤歡迎指出 01. 你對面向?qū)ο笏枷氲睦斫猓?面向?qū)ο缶幊毯喎QOOP,是開發(fā)程序的一種方法、思想。面向...
摘要:近段時間在準(zhǔn)備實(shí)習(xí)的面試,在網(wǎng)上看到一份面試題,就慢慢試著做,爭取每天積累一點(diǎn)點(diǎn)?,F(xiàn)在每天給自己在面試題編寫的任務(wù)是題,有時候忙起來可能就沒有時間寫了,但是爭取日更,即使當(dāng)天沒更也會在之后的更新補(bǔ)上。 ????近段時間在準(zhǔn)備實(shí)習(xí)的面試,在網(wǎng)上看到一份面試題,就慢慢試著做,爭取每天積累一點(diǎn)點(diǎn)。????暫時手頭上的面試題只有一份,題量還是挺大的,有208題,所以可能講的不是很詳細(xì),只是我自...
摘要:公平鎖非公平鎖公平鎖公平鎖是指多個線程按照申請鎖的順序來獲取鎖。加鎖后,任何其他試圖再次加鎖的線程會被阻塞,直到當(dāng)前進(jìn)程解鎖。重量級鎖會讓其他申請的線程進(jìn)入阻塞,性能降低。 Java 中15種鎖的介紹 在讀很多并發(fā)文章中,會提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內(nèi)容如下: 公平鎖 / 非公平鎖 可重入鎖 / 不可重入鎖 獨(dú)享鎖 / 共享鎖 互斥鎖 / 讀...
閱讀 1141·2021-08-12 13:24
閱讀 2989·2019-08-30 14:16
閱讀 3315·2019-08-30 13:01
閱讀 2077·2019-08-30 11:03
閱讀 2779·2019-08-28 17:53
閱讀 3092·2019-08-26 13:50
閱讀 2273·2019-08-26 12:00
閱讀 953·2019-08-26 10:38