2013-02-08 48 views
1

我發現我經常做下面的事情。製作要發送到線程的對象的副本。該線程是唯一一個使用該對象,我們有一個前發生的關係,因此它是線程安全的。在Java中傳遞本地對象線程壞風格?

但這讓我覺得感覺緊張。正如評論所述,如果有人出現並且用objForThread洗過,該怎麼辦? 我應該使用鎖嗎?或者這是一個普遍接受的java模式?

class Example 
{ 
    private SomeObj mDynamicObj = new SomeObj(); 

    public void doWorkInAThread() 
    { 
    mutateThis(mDynamicObj); 
    final SomeObj objForThread = new SomeObj(mDynamicObj); 

    myExecutorService.submit(new Runnable() { @Override public void run() 
    { 
     doSomethingWith(objForThread); 
    }}); 

    mutateThis(mDynamicObj); 

    // Concerned that in the future someone will come 
    // along and mutate objForThread here making this thread unsafe 
    } 
} 
+2

我看不出有什麼不妥。 'objForThread'可以訪問的範圍非常小。 – millimoose 2013-02-08 22:56:45

+0

您的疑慮是有效的。將可變對象傳入線程是很危險的。有一件事要考慮的是將它傳遞給一個類構造函數,至少你會很容易地看到線程正在使用它。複製構造函數還允許線程擁有它自己的對象副本。 – Gray 2013-02-08 22:57:18

+1

這很好,如果'objForThread'是線程安全的,或者更經常的,不可變的。 – 2013-02-08 22:58:21

回答

0

這一切都取決於你想要達到的目標。 有些數據旨在被多個線程訪問和修改。 某些數據僅用於線程安全環境。

如果你需要更詳細的解釋,你必須提供一個真實的例子。

此外,有些類被設計爲線程安全或不可變的。例如,讓String或Integer共享是非常好的。然而,對這些對象的實際引用可能會改變,所以如果你依賴這樣的引用,那麼你可能會遇到問題。

在你的例子中,後者不是這樣,因爲你通過final變量引用對象。但是,如果要引用成員變量mDynamicObject,那麼如果另一個線程中的某人爲其分配了不同的對象(mDynamicObject = new SomeObj()),則會出現問題。如果沒有正確的同步,它可能會導致您的應用程序出現奇怪的狀態。爲了避免這種情況,您可以將其分配給最終變量和參考。

考慮將盡可能多的參數作爲參數傳遞給新線程調用,而不是引用它們。這將保證你參考不會被改變。

當然,如果需要,對象本身最好是不可變的或正確同步的。

1

如果你感到緊張,你最好通過參考線程,而不會將其本地:

class Example 
{ 
    private SomeObj mDynamicObj = new SomeObj(); 

    public void doWorkInAThread() 
    { 
     class MyRunnable implements Runnable 
     { 
      private final SomeObj objForThread; 

      public MyRunnable (SomeObj objForThread) 
      { 
       this.objForThread = objForThread; 
      } 

      @Override 
      public void run() 
      { 
       doSomethingWith (objForThread); 
      } 
     } 

     mutateThis (mDynamicObj); 

     myExecutorService.submit (new MyRunnable (new SomeObj (mDynamicObj))); 

     mutateThis (mDynamicObj); 
    } 
} 
0

保衛你的代碼對人民作出可能打破它是很難改變。

你可能會認爲這不是你的問題。您可以添加警告評論並繼續。或者你可以假設下一個人聰明/小心地弄清楚他的變化的影響。

或者您可以採取防禦措施,如將SomeObj更改爲線程安全或甚至不可變......即使這可能會增加額外的運行時間開銷。

哪種方法最好?我不認爲我可以就此提出建議。這取決於更高層次的問題;例如團隊及其代碼審查和測試程序有多​​好,總體應用程序有多複雜,性能有多關鍵,錯誤多嚴重等等。


對於這個特殊的「榜樣」,你已經抽離任何類似應用程序邏輯,這使得它很難知道哪種方法是最好的。傳遞本地對象是「好」還是「差」取決於上下文。