2012-02-29 12 views
10

使用synchronized我希望這將是足夠的信息,所以在這裏不言而喻。如果您需要更多信息,請在評論中註明。當在Java

我有了兩個內部類的類。內部類每個都有兩個方法在外部類中調用一個方法。因此,它看起來像這樣:

public OuterClass { 
    private boolean outerMethodHasBeenCalled = false; 

    private void outerMethod() { 
     if(!outerMethodHasBeenCalled) { 
      // do stuff 
     } 

     outerMethodHasBeenCalled = true; 
    } 

    private FirstInnerClass { 
     public void someMethod() { 
      outerMethod(); 
     } 
    } 

    private SecondInnerClass { 
     public void someOtherMethod() { 
      outerMethod(); 
     } 
    } 
} 

重要的是要注意這一點很重要:

  • 這是一個Android應用程序。的FirstInnerClassSecondInnerClass實例被傳遞到的WebView的JavaScript接口,所以someMethodsomeOtherMethod可以稱爲在任何時間,在任何特定的順序。
  • 我現在有地方outerMethod被稱爲在準確的同一時間幾乎與現有的代碼有問題(不synchronized關鍵字)(我打印出日誌信息,他們正在加蓋時間戳第二的第1000個)的不同的對象。我的應用程序然後'做了'兩次,因爲當調用outerMethod時,outerMethodHasBeenCalled仍然是錯誤的。這並不好,這正是我想要阻止的。我的應用程序應該只做一次,只做一次:第一次調用outerMethod
  • 聽起來好像我有OuterClass多個實例,但請放心,它的的OuterClass只有一個實例。

重要的是,我的應用程序'做的東西'只有第一次outerMethod被調用(我希望現在很明顯)。所有後續調用基本上被忽略。無論哪個班級首先呼叫outerMethod - 無所謂。

那麼,是不是適合使用synchronized關鍵字在這種情況下?

回答

19

是啊,給你在前面已經奠定了什麼,我想一起去:

private synchronized void outerMethod() { 
... 
} 

注意,這將會阻塞調用者,直到outerMethod之一的副作用()完成。如果這是可以接受的,很酷。如果目的僅僅是在outerMethod()的代碼運行一次,這是第二個主叫不,如果第一個來電正在運行outerMethod()被推遲OK,你可能會考慮:

public OuterClass { 
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean(); 

    private void outerMethod() { 
     if (outerMethodHasBeenCalled.compareAndSet(false, true)) { 
      // do stuff 
     } 
    } 
... 

查看JavaDoc for AtomicBoolean以瞭解發生了什麼(假設它在Android的Java中可用)。

+9

+1爲AtomicBoolean,學到了新的東西:) – quaylar 2012-02-29 07:28:00

7

裹一切要在同步塊只運行一次outerMethod

private void outerMethod() { 
    synchronized (this) { 
     if(!outerMethodHasBeenCalled) { 
      // do stuff 
     } 

     outerMethodHasBeenCalled = true; 
    } 
} 

這樣,第一次調用該方法,只有一個線程將被允許進入同步塊在時間。第一個將執行if語句中的代碼,然後將outerMethodHasBeenCalled設置爲true。其他線程會看到它是真的,並跳過if代碼。

+0

您是否還需要將標誌'volatile'(以便其他線程可以可靠地查看更改)?也許使用AtomicBoolean來保證安全。 – Thilo 2012-02-29 07:06:28

+1

@Thilo:如果所有對該標誌的訪問都在同步塊內,則不需要使用volatile。Java內存模型確保更改將可見。 AtomicBoolean和volatile在你不想擁有一個完全同步塊的代價時很有用,儘管它們使用起來比較麻煩。 – Avi 2012-02-29 07:13:42

+2

@Thilo不,你不需要,如果outerMethodHasBeenCalled被訪問的唯一地方是在outerMethod中。 synchronized關鍵字表示內存同步屏障。閱讀關於synchronized關鍵字的VM規範。順便說一句,請不要只是爲了安全起見。正確理解你寫的內容和含義。其他程序員會在您理解之後進入您的代碼中,暫時將其側重於試圖找出爲什麼使用某個構造的原因。 「他必須使用揮發性的原因,我沒有看到什麼?」 – brettw 2012-02-29 07:14:03