2015-04-12 118 views
3

對於這個簡單的同步聲明:同步語句 - 同步方法和同步語句是否相同?

public void addName(String name) { 
    synchronized(this) { // line1 
     lastName = name; 
     nameCount++; 
    } 
    nameList.add(name); 
} 

看來這兩個線程可以說t1t2可以調用在同一時間的addName方法,但一旦得到行評價爲line1,只有一個線程可以繼續,這意味着其他線程將不得不暫停。這意味着即使將nameList放在synchronized語句之外,也可以保證nameList不會被多個線程衝突。

這是真的嗎?如果是的話,那麼有沒有下面的方法之間的區別,如果沒有已進入同步語句之前完成:

public void addName(String name) { 
    synchronized(this) { //line1 
     lastName = name; 
     nameCount++; 

     nameList.add(name); 
    } 
} 

或者:

public synchronized void addName(String name) { 
     lastName = name; 
     nameCount++; 
     nameList.add(name); 
} 

我知道正是

void synchronized add(){ 

} 

與上述相同:

void add(){ 
    synchronized(this){ 

    } 
} 

什麼讓我感到困惑的是,在addName例子,我想執行順序可能是這樣的:

t1:synchronized steatement 
t1:nameList.add 
t2:synchronized steatement 
t2:nameList.add 

這意味着沒有爲synchronized statementnameList.add之間的其他線程執行沒有變化。所以將nameList.add放在我們的同步塊外部沒有區別。

但實際上,執行可能看起來像這樣由@JB Nizet答案:

t1:synchronized steatement 
t2:synchronized steatement 

t2:nameList.add 
t1:nameList.add 

然後把nameList外部或塊內是很重要的。

+0

它們是等價的(後兩個)。 – Maroun

+0

哦,是的,我忘了:) – hguser

+0

https://stackoverflow.com/questions/574240/is-there-an-advantage-to-use-a-synchronized-method-instead-of-a-synchronized-blo ?rq = 1有很多關於同步方法和塊之間差異的鏈接或相關問題。 –

回答

4

最後兩個片段是等價的,但第一個片段不是。

在第一個片段中,考慮到列表的添加不是同步塊的一部分,兩個線程可以同時執行該指令。如果列表不是線程安全的,那麼這是一個問題。

即使列表是線程安全的,它也可能是一個問題,因爲狀態的各個部分(計數,姓氏和列表)的更改不是自動進行的。其他線程因此可能會看到姓氏的新值,但在列表中找不到這個姓氏。

+0

謝謝我明白了,我認爲只要同步語句完成,一個線程就會調用'nameList.add',而沒有任何其他線程可以交錯。但實際上,'nameList.add'可以同時訪問。 – hguser