JAVA學習筆記(併發程式設計
阿新 • • 發佈:2018-12-17
什麼是釋出物件和物件逸出
- ◆釋出物件:使一個物件能夠被當前範圍之外的程式碼所使用
- ◆物件逸出:一種錯誤的釋出。當一個物件還沒有構造完成時,就使它被其他執行緒所見
不正確的釋出可變物件導致的兩種錯誤:
- 釋出執行緒意外的所有執行緒都可以看到被髮布物件的過期的值
- 執行緒看到的被髮布物件的引用是最新的,然而被髮布物件的狀態卻是過期的
下面看下不安全的示例
package com.mmall.concurrency.example.publish;
import com.mmall.concurrency.annoations.NotRecommend;
import com.mmall.concurrency. annoations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;
/**
* 物件溢位
*在物件構造沒有完成之前就會被髮布;有可能有不安全因素
*/
@Slf4j
@NotThreadSafe
@NotRecommend
public class Escape {
private int thisCanBeEscape=0;
public Escape(){
new InnerClass();
}
private class InnerClass{
public InnerClass (){
log.info("{}",Escape.this.thisCanBeEscape);
}
}
public static void main(String[] args) {
new Escape();
}
}
/*
在以上這個例子中,內部類的構造器裡包含了對封裝例項的隱含引用,這樣在物件沒有被正確構造完成之前就會被髮布,由此會導致不安全的因素在裡面。
其中一個就是導致this引用在構造期間逸出的錯誤,它是在建構函式構造過程中啟動了一個執行緒,無論是顯式啟動還是隱式啟動,都會造成this引用的逸出。新執行緒總會在所屬物件構造完畢之前就已經看到它了,所以如果要在建構函式中建立執行緒,那麼不要啟動它,而是應該採用一個專有的start,或是其他初始化的方式統一啟動執行緒。這裡其實我們可以使用工廠方法和私有建構函式來完成物件建立和監聽器的註冊等等來避免不正確的釋出。
*/
package com.mmall.concurrency.example.publish;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
/**
* 不安全的物件釋出
* 其他執行緒可修改
*/
@Slf4j
public class UnSafePublish {
private String[] states={"a","b","c"};
public String[] getStates(){
return states;
}
public static void main(String[] args) {
UnSafePublish unSafePublish = new UnSafePublish();
log.info("{}",Arrays.toString(unSafePublish.getStates()));
unSafePublish.getStates()[0]="d";
log.info("{}",Arrays.toString(unSafePublish.getStates()));
}
}
/*
15:15:21.725 [main] INFO com.mmall.concurrency.example.publish.UnSafePublish - [a, b, c]
15:15:21.734 [main] INFO com.mmall.concurrency.example.publish.UnSafePublish - [d, b, c]
*/