簡單來說就是提供一個物件的引用給作用域之外的程式碼。例如return一個對象,或是作為參數傳遞到其他類別的方法。
不安全的發布物件範例:
<code>@Slf4j</code><code>@NotThreadSafe</code><code>public class UnsafePublish {</code><code><br></code><code> private String[] states = {"a", "b", "c"};</code><code><br></code><code> public String[] getStates() {</code><code> return states;</code><code> }</code><code><br></code><code> public static void main(String[] args) {</code><code> UnsafePublish unsafePublish = new UnsafePublish();</code><code> log.info("{}", Arrays.toString(unsafePublish.getStates()));</code><code> // 发布对象不安全,可被修改</code><code> unsafePublish.getStates()[0] = "d";</code><code> log.info("{}", Arrays.toString(unsafePublish.getStates()));</code><code> }</code><code>}</code>
如果一個類別還沒建構結束就已經提供給了外部程式碼一個物件參考即發布了該對象,此時叫做物件逸出,物件的逸出會破壞線程的安全性。
<code>public class Escape {</code><code> private int thisCanBeEscape = 1;</code><code><br></code><code> public Escape() {</code><code> new InnerClass();</code><code> // 还有业务需要执行</code><code> thisCanBeEscape++;</code><code> }</code><code><br></code><code> private class InnerClass {</code><code> public InnerClass() {</code><code> log.info("{}", Escape.this.thisCanBeEscape);</code><code> }</code><code> }</code><code><br></code><code> public static void main(String[] args) {</code><code> new Escape();</code><code> }</code><code>}</code>
這個內部類別的實例裡麵包含了對封裝實例的私有域物件的引用,在物件沒有被正確建構完成之前就會被發布,有可能有不安全的因素在裡面,會導致this引用在構造期間溢出的錯誤。
上述程式碼在函數建構過程中啟動了一個執行緒。無論是隱式的啟動還是明確的啟動,都會造成這個this引用的溢位。新線程總會在所屬物件建構完畢之前就已經看到它了。
「類別名稱.this」的語法在Java語言中叫做「qualified this」。這個語法的主要用途是:在內部類別的方法中,要指定某個嵌套層次的外圍類別的「this」引用時,使用「外圍類別名稱.this」語法。例如說:
class Foo { class Bar { Foo getFoo() { return Foo.this; } }}
在Foo.Bar類別中的getFoo()方法中,如果直接寫「this」的話所指的是這個Foo.Bar類別的實例,而如果要指定外圍的Foo類別的this實例的話,這裡就得寫成Foo.this。特別的,如果在上例的getFoo()方法中寫Bar.this的話,作用就跟直接寫this一樣,指定的是當前的Foo.Bar類別實例。
在靜態初始化函數中初始化一個物件參考
將物件的參考保存到volatile類型域或AtomicReference物件中
安全共享物件策略
以上是Java中如何發布和避免物件逸出問題?的詳細內容。更多資訊請關注PHP中文網其他相關文章!