首頁  >  文章  >  Java  >  Java中如何發布和避免物件逸出問題?

Java中如何發布和避免物件逸出問題?

WBOY
WBOY轉載
2023-04-22 14:37:08960瀏覽

發佈物件

簡單來說就是提供一個物件的引用給作用域之外的程式碼。例如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的解釋說明

「類別名稱.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類別實例。

安全發布物件

  1. 在靜態初始化函數中初始化一個物件參考

  2. 將物件的參考保存到volatile類型域或AtomicReference物件中

  3. ##將物件的參考儲存到某個正確建構物件的final型別域中

  4. ##將物件的參考儲存到一個由鎖定保護的域中
可以聯想下單例模式中餓漢模式/懶漢模式。

安全共享物件策略

    執行緒限制:一個被執行緒限制的對象,由執行緒獨佔,並且只能被佔有它的執行緒修改。
  1. 共享唯讀:一個共享唯讀的對象,在沒有額外同步的情況下,可以被多個執行緒並發訪問,但是任何執行緒都不能修改它。
  2. 線程安全物件:一個線程安全的物件或容器,在內部透過同步機制來保證線程安全,所以其他線程無需額外的同步就可以透過公共介面隨意存取它。
  3. 被守護物件:被守護物件只能透過取得特定的鎖定來存取。
  4. #

以上是Java中如何發布和避免物件逸出問題?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除