2011-01-22 86 views

回答

8

如果你的方法只對參數和本地定義的(而不是類成員)變量進行操作,那麼需要擔心的是零同步問題。

但是......

這意味着你用必須生活和你的方法的範圍內死亡只有任何可變引用類型。 (不可變的引用類型是不是這裏有問題。)例如,這是沒有問題的:

int doSomething(int myParameter) 
{ 
    MyObject working_set = new MyObject(); 
    interim = working_set.doSomethingElse(myParameter); 
    return working_set.doSomethingElseAgain(interim); 
} 

一個MyObject實例你的方法中創建的,做所有的工作在你的方法,並咳血,等待當你退出你的方法時,由GC來剔除。

此,在另一方面,可能是一個問題:

int doSomething(int myParameter) 
{ 
    MyObject working_set = new MyObject(); 
    interim = working_set.doSomethingElse(myParameter); 
    another_interim = doSomethingSneaky(working_set); 
    return working_set.doSomethingElseAgain(another_interim); 
} 

除非你肯定知道發生了什麼事在doSomethingSneaky(),您可能需要同步的地方。具體而言,您可能必須在working_set上執行同步操作,因爲doSomethingSneaky()可能會存儲對本地working_set對象的引用,並在您仍在執行方法或working_set方法中的操作時將該引用傳遞給另一個線程。在這裏你必須更加防守。

當然,如果您只使用原始類型,即使調用其他方法,傳遞這些值也不會成爲問題。

+0

「任何引用類型」應該可以是「任何_mutable_引用類型」...不可變對象不是問題。 – ColinD 2011-01-22 20:08:26

0

您不需要擔心局部變量。但是實例變量是值得關注的。

4

是否只使用局部變量的方法,不會遇到任何線程問題?

在一個非常簡單的道理沒錯,但讓是明確的 - 我想如果這是唯一真正:

  • 這種方法只使用局部變量是原語或引用可變的情況下,可以不否則通過任何其他方式訪問該方法之外。

  • 這樣的方法只調用線程安全的方法。

的一些方法,這些規則可能被侵犯:

  • 的局部變量可以被初始化爲指向一個對象,這也是該方法外部訪問。例如,局部變量可能指向單例(Foo bar = Foo.getSingleton())。

  • 如果將實例作爲參數傳遞給保存對實例的引用的外部方法,則由本地變量持有的本地實例可能會「泄漏」。

  • 沒有實例變量並且只有一個沒有局部變量的方法的類仍然可以調用另一個不是線程安全的類的靜態方法。

1

該問題是非常通用的,所以請不要指望我的答案有任何特異性。

1_我們需要比靜態方法更小心,而不是說實例方法。

2_ @Justmycorrectopinion是正確的,但他描述的一些術語需要更詳細地闡述爲完美。 (即使靜態方法只適用於局部變量,仍然存在競態條件的可能性。)

3_對於我來說,有一些簡單的規則可以幫助我分析線程安全性。

瞭解封裝在其中的每個組件是否可共享。所以最簡單的解決方案是減少所有變量的範圍,並且如果絕對必要的話只增加範圍,並且如果組件在對象上執行突變,則它通常不是線程安全的。

4_使用工具支持對線程安全執行靜態代碼分析。 (Idea有checkthread插件)。

5_永遠不要使用靜態方法來執行對象變異。如果調用靜態變量導致對象變異,那麼開發人員只是繞開OOPS。

6_始終記錄線程安全性。記住一些方法在開發時可能不需要同步,但可以非常容易地使線程安全。

7_最後但可能是我最重要的一點,請確保大部分對象是不可變的。根據我的經驗,大多數時候,我從來沒有必須讓很多對象變化。 (在極少數情況下,當對象狀態需要更改時,防禦性複製/新建對象創建幾乎總是更好。)

相關問題