2012-07-17 67 views
2

我有一個數據變量monthArray,它由多個使用者讀取並定期由單個定期更新程序線程更新。全部是異步的。同步的代碼塊只對塊進行分配或整個塊體?

我已經考慮了這兩個選項來安全地執行更新。

ArrayList<String> tempArray = ModelJob.getDistinctMonths(user, true);  
    synchronized (monthArray) { 
     monthArray = tempArray; 
    } 

synchronized (monthArray) { 
     monthArray = ModelJob.getDistinctMonths(user, true); 
    } 

後面的第一個是該ModelJob.getDistinctMonths(user, true);呼叫非常耗時,而且我不想持有synchrinzation阻止更長那麼它,只爲快速的想法使用更新的數組重新分配舊數組。但似乎是一個混淆,我只想做,如果完全nessecary。任何人都可以告訴我jvm如何處理這種同步和天氣或不做前者會給我什麼增加性能?基本上我問如果jvm會阻塞整個靜態ModelJob調用,或者它只能阻止重新分配並且安全,如果是的話,如果它足夠聰明的話。

+1

一個空塊'synchronized(monthArray){}'仍然會等待獲得一個鎖。該塊的內容並不重要。 – 2012-07-17 14:11:50

回答

3

假設你不需要圍繞getDistinctMonths()調用同步(即調用是線程安全的,你不需要調用和賦值周圍的原子),那麼你可以分配各地同步(是的,阻塞僅限於同步塊,否則語法將毫無意義)。請注意,@JohnVint提供了一個很好的觀點,您不應該在修改時參照monthArray參考進行同步。您必須在不更改的單獨對象實例上進行同步。

最後,您可以刪除同步塊並使monthArray成員變爲易失性並獲得相同的結果。

+0

即使有很多更新程序線程,它也同樣是線程安全的。第二個版本實際上與'volatile'具有完全相同的語義(當然,假設'同步'讀取)。 – 2012-07-17 14:25:24

+0

@MarkoTopolnik - 是的,但有了多個更新線程,您最終可能會丟失「最新」數據(取決於哪個線程最後更新了引用)。同步版本的情況也是如此,具體取決於您對同步塊的範圍,但我主要指出,如果使用單個更新線程,則沒有任何問題,您可以使用volatile。 – jtahlborn 2012-07-17 15:29:37

+0

你可以刪除你對一個作家線程的假設,你的語句也會如此,如果不是'更真實的':-) – 2012-07-17 16:42:36

1

如果您只將volatile修飾符放在monthArray上並刪除所有​​塊,那麼您將擁有無鎖線程安全性。

此外,JVM可能會優化您的清理程序(第二個)版本的代碼以執行,就好像它是第一個版本一樣。所以,如果保持鎖定,更好地堅持更清潔的版本。

1

從性能的角度來看,使用第一種方法會更好。這將避免不必要的同步。

你必須記住的一件事情是,即使是在monthArray上的閱讀將需要同步。只有同時使用相同的對象鎖同步更新和讀取時,同步才起作用。我寧願使用類對象鎖。例如,如果這個碼是類ModelUpdate的一部分,然後使用以下代碼

synchronized(ModelUpdate.class) { 
     monthArray = tempArray; 
} 
1

甲同步塊將總是在其整個執行方框。作爲參數給出的對象(monthArray)被稱爲「監視器」,並將保證所有其他同步對象(monthArray)作爲參數的同步塊將被異步執行。

1

這裏一個明顯的缺陷是,你不應該在將要改變的對象上同步。

我寧願第一個例子,而是使用一個共同的鎖

final Object lock = new Object(); 

synchronized(lock){ 
    monthArr = ...; 
} 

然而,由於大多數人認爲,宣佈monthArr volatile將具有相同的效果。