2012-12-17 63 views
35

是否有任何通用的方式或規則退出,我們可以通過該方式或規則退出來確保特定用於任何應用程序的各種Utility類中的靜態方法的線程安全性。這裏我想具體指出Web應用程序的線程安全性。如何確保實用靜態方法的線程安全?

衆所周知,以不可變對象作爲參數的靜態方法是線程安全的,可變對象不是。

如果我有一個對java.util.Date的某些操作的實用方法,並且該方法接受java.util.Date的實例,那麼此方法將不是線程安全的。那麼如何在不改變參數傳遞方式的情況下使線程安全?

public class DateUtils { 

    public static Date getNormalizeDate(Date date) { 
     // some operations 
    } 
} 

也是類javax.faces.context.FacesContext可變嗎?將此類的實例傳遞給靜態工具方法是否安全?

該列表中的實例可以或不可以作爲參數傳遞的類的列表可能很長;所以在編寫這類實用程序類的代碼時,我們應該牢記什麼?

+2

爲什麼投票和一個關閉請求?這是一個錯誤的問題嗎? –

+0

你有沒有考慮過這個靜態方法'synchronized'? –

+6

@AndrewLogvinov是的,我想過。但我不想在不知道爲什麼要這樣做的情況下同步一個方法。我們應該在什麼情況下使靜態方法同步? –

回答

46

衆所周知,具有不可變對象作爲參數的靜態方法是線程安全的,可變對象不是。

我會抗衡這個。傳遞給方法的參數存儲在一個堆棧中,這是一個每線程的習慣用法。

如果您的參數是一個可變對象,如Date那麼您需要確保其他線程不在同一時間在其他地方修改它。但這與你的方法的線程安全性無關。

您發佈的方法是線程安全的。它不保持任何狀態,只對其參數進行操作。

我強烈建議您閱讀Java Concurrency in Practice,或致力於Java中的線程安全的類似書。這是一個複雜的問題,無法通過幾個StackOverflow答案適當解決。

+0

很好的答案,謝謝 – Keerthivasan

3

我建議一旦方法啓動並使用副本而不是原始參數創建該(可變)對象的副本。

像這樣的事情

public static Date getNormalizeDate(Date date) { 
    Date input = new Date(date.getTime()); 
    // ... 
} 
+2

對於Date來說這聽起來不錯,但對於自定義對象來說不可能,特別是如果它是第三方自定義對象,他不能編輯。 –

11

由於類並無持有任何成員變量,你的方法是無狀態的(它僅使用局部變量和參數),因此是線程安全的。

調用它的代碼可能不是線程安全的,但這是另一個討論。例如,Date不是線程安全的,如果調用代碼讀取由另一個線程寫入的Date,則必須在Date寫入和讀取代碼中使用正確的同步。

4

鑑於JVM的結構,本地變量,方法參數和返回值本質上是「線程安全的」。但是如果你適當地設計你的類,實例變量和類變量只會是線程安全的。更多here

0

下面是我如何看待它:設想一個CampSite(這是一個靜態方法)。作爲一名露營者,我可以在揹包中引入一堆物品(這是在堆棧中傳遞的參數)。 CampSite爲我提供了一個放置帳篷和野營爐等的地方,但如果CampSite唯一能做的就是讓我修改自己的物體,那麼它就是線程安全的。 CampSite甚至可以憑空創建一些東西(FirePit firepit = new FirePit();),這些東西也會在堆棧中創建。

在任何時候我都可以將我的所有物品都消失在我的草垛中,並且任何其他的露營者都可以出現,做他們最後一次消失時的行爲。此CampSite中的不同線程將無法訪問在其他線程中創建CampSite的堆棧上的對象。

假設只有一個campStove(CampStove的單個對象,而不是單獨的實例)。如果通過一些想象力,我共享一個CampStove對象,那麼需要考慮多線程。我不想打開我的訓練營,消失,然後在其他一些野營者關閉後重新出現 - 我會永遠檢查我的熱狗是否完成,永遠不會。你將不得不在某個地方......在CampStove類中,在調用CampSite的方法中,或者在CampSite本身中...但像Duncan Jones所說的那樣,「這是另一回事」。

請注意,即使我們在單獨的實例中駐留-靜態CampSite對象,共享一個campStove也會有相同的多線程考慮因素。