2013-08-03 74 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