亚洲免费在线视频-亚洲啊v-久久免费精品视频-国产精品va-看片地址-成人在线视频网

您的位置:首頁技術文章
文章詳情頁

java this引用逃逸詳解

瀏覽:4日期:2022-08-20 11:03:57

1、什么是This逃逸?

在構造器構造還未徹底完成前(即實例初始化階段還未完成),將自身this引用向外拋出并被其他線程復制(訪問)了該引用,可能會問到該還未被初始化的變量,甚至可能會造成更大嚴重的問題。

廢話不多說,看一下代碼

/** * 模擬this逃逸 * @author Lijian * */ public class ThisEscape { //final常量會保證在構造器內完成初始化(但是僅限于未發生this逃逸的情況下,具體可以看多線程對final保證可見性的實現) final int i; //盡管實例變量有初始值,但是還實例化完成 int j = 0; static ThisEscape obj; public ThisEscape() { i=1; j=1; //將this逃逸拋出給線程B obj = this; } public static void main(String[] args) { //線程A:模擬構造器中this逃逸,將未構造完全對象引用拋出 /*Thread threadA = new Thread(new Runnable() { @Override public void run() { //obj = new ThisEscape(); } });*/ //線程B:讀取對象引用,訪問i/j變量 Thread threadB = new Thread(new Runnable() { @Override public void run() { //可能會發生初始化失敗的情況解釋:實例變量i的初始化被重排序到構造器外,此時1還未被初始化 ThisEscape objB = obj; try { System.out.println(objB.j); } catch (NullPointerException e) { System.out.println('發生空指針錯誤:普通變量j未被初始化'); } try { System.out.println(objB.i); } catch (NullPointerException e) { System.out.println('發生空指針錯誤:final變量i未被初始化'); } } }); //threadA.start(); threadB.start(); } }

輸出結果:這說明ThisEscape還未完成實例化,構造還未徹底結束。

發生空指針錯誤:普通變量j未被初始化發生空指針錯誤:final變量i未被初始化

另一種情況是利用線程A模擬this逃逸,但不一定會發生,線程A模擬構造器正在構造...而線程B嘗試訪問變量,這是因為

(1)由于JVM的指令重排序存在,實例變量i的初始化被安排到構造器外(final可見性保證是final變量規定在構造器中完成的);

(2)類似于this逃逸,線程A中構造器構造還未完全完成。

所以嘗試多次輸出(相信我一定會發生的,只是概率相對低),也會發生類似this引用逃逸的情況。

/** * 模擬this逃逸 * @author Lijian * */public class ThisEscape { //final常量會保證在構造器內完成初始化(但是僅限于未發送this逃逸的情況下) final int i; //盡管實例變量有初始值,但是還實例化完成 int j = 0; static ThisEscape obj; public ThisEscape() { i=1; j=1; //obj = this ; } public static void main(String[] args) { //線程A:模擬構造器中this逃逸,將未構造完全對象引用拋出 Thread threadA = new Thread(new Runnable() { @Override public void run() {//構造初始化中...線程B可能獲取到還未被初始化完成的變量//類似于this逃逸,但并不定發生obj = new ThisEscape(); } }); //線程B:讀取對象引用,訪問i/j變量 Thread threadB = new Thread(new Runnable() { @Override public void run() {//可能會發生初始化失敗的情況解釋:實例變量i的初始化被重排序到構造器外,此時1還未被初始化ThisEscape objB = obj;try { System.out.println(objB.j);} catch (NullPointerException e) { System.out.println('發生空指針錯誤:普通變量j未被初始化');}try { System.out.println(objB.i);} catch (NullPointerException e) { System.out.println('發生空指針錯誤:final變量i未被初始化');} } }); threadA.start(); threadB.start(); }}

2、什么情況下會This逃逸?

(1)在構造器中很明顯地拋出this引用提供其他線程使用(如上述的明顯將this拋出)。

(2)在構造器中內部類使用外部類情況:內部類訪問外部類是沒有任何條件的,也不要任何代價,也就造成了當外部類還未初始化完成的時候,內部類就嘗試獲取為初始化完成的變量

在構造器中啟動線程:啟動的線程任務是內部類,在內部類中xxx.this訪問了外部類實例,就會發生訪問到還未初始化完成的變量 在構造器中注冊事件,這是因為在構造器中監聽事件是有回調函數(可能訪問了操作了實例變量),而事件監聽一般都是異步的。在還未初始化完成之前就可能發生回調訪問了未初始化的變量。

在構造器中啟動線程代碼實現:

/** * 模擬this逃逸2:構造器中啟動線程 * @author Lijian * */public class ThisEscape2 { final int i; int j; public ThisEscape2() { i = 1; j = 1; new Thread(new RunablTest()).start(); } //內部類實現Runnable:引用外部類 private class RunablTest implements Runnable{ @Override public void run() { try {System.out.println(ThisEscape2.this.j); } catch (NullPointerException e) {System.out.println('發生空指針錯誤:普通變量j未被初始化'); } try {System.out.println(ThisEscape2.this.i); } catch (NullPointerException e) {System.out.println('發生空指針錯誤:final變量i未被初始化'); } } } public static void main(String[] args) { new ThisEscape2(); }}

構造器中注冊事件,引用網上的一段偽代碼將以解釋:

public class ThisEscape3 { private final int var; public ThisEscape3(EventSource source) { //注冊事件,會一直監聽,當發生事件e時,會執行回調函數doSomething source.registerListener( //匿名內部類實現 new EventListener() {public void onEvent(Event e) {  //此時ThisEscape3可能還未初始化完成,var可能還未被賦值,自然就發生嚴重錯誤 doSomething(e);} } ); var = 10; } // 在回調函數中訪問變量 int doSomething(Event e) { return var; }}

3、怎樣避免This逃逸?(1)單獨編寫一個啟動線程的方法,不要在構造器中啟動線程,嘗試在外部啟動。

...private Thread t;public ThisEscape2() { t = new Thread(new EscapeRunnable());}public void initStart() { t.start();}...

(2)將事件監聽放置于構造器外,比如new Object()的時候就啟動事件監聽,但是在構造器內不能使用事件監聽,那可以在static{}中加事件監聽,這樣就跟構造器解耦了

static{ source.registerListener( new EventListener() {public void onEvent(Event e) { doSomething(e);} } ); var = 10; }}

4、總結

this引用逃逸問題實則是Java多線程編程中需要注意的問題,引起逃逸的原因無非就是在多線程的編程中“濫用”引用(往往涉及構造器中顯式或隱式地濫用this引用),在使用到this引用的時候需要特別注意!

同時這會涉及到:final的內存語義,即final域禁止重排序問題(2020.11.22增加),包括寫final域與讀final域重排序兩個規則(參考資料《Java并發編程的藝術》)

以上就是java this引用逃逸詳解的詳細內容,更多關于java this引用逃逸的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 三级视频在线播放 | 国产一级一国产一级毛片 | 久久91精品国产99久久yfo | 99re热在线视频 | 国产成人免费手机在线观看视频 | 91视频久久| 免费一级a毛片在线播 | 欧美成人高清性色生活 | 三级a黄| 国产精品欧美韩国日本久久 | 国产精品国产精品 | 国产a国产片国产 | 99视频在线精品自拍 | 91成人午夜在线精品 | www.91亚洲| 欧美18www| 国产精品久久国产三级国电话系列 | 亚洲天堂网视频 | 日韩成人中文字幕 | 在线观看国内自拍 | 精品国产一区二区三区不卡蜜臂 | 中文久草 | 国产综合成人亚洲区 | 欧美激情性色生活片在线观看 | 亚洲午夜精品一级在线 | 91日本在线视频 | 一区二区三区网站在线免费线观看 | 大学生久久香蕉国产线观看 | 国产a国产 | 性欧美精品孕妇 | 美女视频一区二区三区在线 | 久久精品爱 | a级毛片在线看日本 | a在线观看欧美在线观看 | 日韩一级欧美一级毛片在线 | 亚洲欧美国产精品久久久 | 日韩专区亚洲综合久久 | 国产喷水女王在线播放 | 色偷偷在线刺激免费视频 | 欧洲女同互慰在线视频 | 国内精品七七久久影院 |