定義: 是一個對象可以被當前範圍以外的代碼所使用
一種錯誤的發佈。當一個對象該沒有構造完成時,就使被其餘線程所見。
下面咱們來看一下沒有安全發佈的對象java
@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())); } }
咱們看這段代碼,咱們建立了一個對象經過getStates方法咱們能夠獲取這個對象的數組,此時咱們將數組內容打印出來結果,若是此時咱們將這個對象發佈出去,而後其餘線程(這裏沒有模擬其餘線程對其修改)又對這個對象的states的值進行修改,此時在拿到這個對象的指望的是沒有被修改的,事實上獲得的對象是修改事後的。也就是說咱們不能直接經過一個public的一個set方法就行return。數組
下面咱們再看一段對象溢出的代碼安全
public class ThisEscape { public ThisEscape(EventSource source) { source.registerListener(new EventListener() { public void onEvent(Event e) { doSomething(e); } }); } void doSomething(Event e) { } interface EventSource { void registerListener(EventListener e); } interface EventListener { void onEvent(Event e); } interface Event { } }
這將致使this逸出,所謂逸出,就是在不應發佈的時候發佈了一個引用。在這個例子裏面,當咱們實例化ThisEscape對象時,會調用source的registerListener方法,這時便啓動了一個線程,並且這個線程持有了ThisEscape對象(調用了對象的doSomething方法),但此時ThisEscape對象卻沒有實例化完成(尚未返回一個引用),因此咱們說,此時形成了一個this引用逸出,即尚未完成的實例化ThisEscape對象的動做,卻已經暴露了對象的引用。其餘線程訪問尚未構造好的對象,可能會形成意料不到的問題。函數
public class SafeListener { private final EventListener listener; private SafeListener() { listener = new EventListener() { public void onEvent(Event e) { doSomething(e); } }; } public static SafeListener newInstance(EventSource source) { SafeListener safe = new SafeListener(); source.registerListener(safe.listener); return safe; } void doSomething(Event e) { } interface EventSource { void registerListener(EventListener e); } interface EventListener { void onEvent(Event e); } interface Event { } }
在這個例子中咱們使用匿名類的形式來構造,只有在整個對象都實例化好了才能會執行。只有當構造函數返回時,this引用才應該從線程中逸出。構造函數能夠將this引用保存到某個地方,只要其餘線程不會在構造函數完成以前使用它this