2012-10-31 79 views
2

我在問這個問題只是爲了好奇,我知道做這種事情是愚蠢的。線程進入同步塊後我們可以改變鎖嗎?

public void doSomething() 
{ 
     synchronized(object_A){ 
     count++; 
     average = count/total; 
     } 
} 

現在,讓我們說我有2個線程同時運行(調用函數DoSomething的()),而第一個線程已經進入塊,讓該行「算++」說,第二個線程被阻塞,等待鎖。

現在我試着做object_A = new LockObject()(在另一個線程中)。現在線程1和線程2發生了什麼?

線程2是否會進入該塊?由於它已經執行了語句「synchronized(object_A)」,所以更改鎖是否太遲了?

線程1會在同步塊(假設線程1仍在塊中)時更改鎖嗎?

+2

線程1不會更改鎖定。它保存由變量object_A引用的對象上的鎖;一旦它獲得鎖定,它會忘記變量。你甚至可以'synchronized(someMethod()){}' – ignis

+0

關於線程2,我猜(但我可能是錯的)它仍然會爭奪第一個鎖。 [JLS 7](http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.19)說,1.表達式被評估,之後2.線程獲取鎖,但是3.當另一個線程持有鎖時,線程不能做2。因此,在我看來,線程2將不會重新讀取變量的引用,從而使變量賦值無效。 – ignis

+0

無論如何,您應該知道這裏還有一個問題 - 如果變量賦值不是易失性的,並且在賦值後沒有發生同步,則變量賦值可能無效。這是因爲允許線程創建變量的本地副本,並且只需要更新volatile/synchronized上的本地副本。 – ignis

回答

1

這就像ignis說的,但是線程2將在線程1完成後看到新的引用,因爲它必須刷新所有變量。

+0

這是關於volatile/synchronized的第三條評論,我同意Thread 2會看到更新後的變量。但這並不意味着線程2會鎖定新的對象,請參閱我對jls的第二條評論。 – ignis

0

唯一的問題是數據的完整性。線程將在不同的鎖上進行同步,並且由鎖保護的數據將具有錯誤的值。鎖在實例初始化程序的私有最終字段中或在類的構造函數中創建。