安全發佈對像

發佈對像

定義: 是一個對象可以被當前範圍以外的代碼所使用

對象溢出

一種錯誤的發佈。當一個對象該沒有構造完成時,就使被其餘線程所見。

下面咱們來看一下沒有安全發佈的對象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

相關文章
相關標籤/搜索