2013-08-03 19 views
5

代碼段 - 1同步訪問不可變整數對象

class RequestObject implements Runnable 
{ 
    private static Integer nRequests = 0; 

    @Override 
    public void run() 
    {  
     synchronized (nRequests) 
     { 
      nRequests++; 
     } 
    } 
} 

代碼段 - 2

class RequestObject implements Runnable 
{ 
    private static Integer nRequests = 0; 
    private static Object lock = new Object(); 

    @Override 
    public void run() 
    {  
     synchronized (lock) 
     { 
      nRequests++; 
     } 
    } 
} 

雖然第二代碼段,而不會造成任何競爭條件工作正常,則第一個在同步類(RequestObject)的不同實例之間同步對靜態數據成員的訪問方面沒有成功。有人可以更多地指出這一點。我想了解爲什麼第一種方法不起作用。

我原來的實現是第一個。後來我在https://stackoverflow.com/a/2120409/134387看到。

+3

因爲'整數'是不可變的。增加它不是做你認爲 –

+1

也不使用Integer,使用'int' –

+0

這是一個不同的問題。請讓它成爲一個新問題。 –

回答

6

您正在不斷創建新的Integer對象,然後您將其同步,至少使其非常困​​惑。所以,你可以得到以下情形:

線程A被持有nRequests的當前值(可以說0)

爲相同的值(0)

線程A增加nRequests線程B隊列(到值1)

線程C獲取新值並在其上同步,增加它並放棄該值。

線程A放開監視器0

線程B同步0和它增加至1,覆蓋的Ç

的變化在第二種方法中,你有一個對象,每個人都必須同步。這正是你想要的。

4

Integer的實例是不可變的,因此創建一個新的Integer對象來保存結果,並將其存儲在nRequests中。​​語句在一個對象上同步。因此,線程將在不同的對象上同步。是的,同一個對象上的同步塊中可能同時只有一個線程,但同一時間不同對象的同步塊中可能只有一個線程...

最簡單的同步訪問方法靜態是把它在一個靜態同步方法:

static synchronized void increment() { 
    nRequests++; 
} 

這等同於下面的同步塊:

synchronized (RequestObject.class) { 
    nRequests++; 
} 

其中RequestObject是包含靜態字段的類。

2

問題是Integer類在java中是不可變的。所以每個線程都在不同的對象上同步,因爲nRequests++在每次調用時都會創建一個新對象。

在第二種情況下,每個實例的lock對象都是相同的,並將線程的訪問權序列化爲變量nRequests