【问题标题】:Synchronizing access to Immutable Integer object同步访问不可变整数对象
【发布时间】:2013-08-03 07:32:54
【问题描述】:

代码 sn-p - 1

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

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

代码 sn-p - 2

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

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

虽然第二个代码 sn-p 工作正常而不会导致任何竞争条件,但第一个代码在同一类 (RequestObject) 的不同实例之间同步对静态数据成员的访问并不成功。有人可以对此进行更多说明。我想了解为什么第一种方法不起作用。

我最初的实现是第一个。后来在https://stackoverflow.com/a/2120409/134387看到的。

【问题讨论】:

  • 因为Integer 是不可变的。增加它并没有按照您的想法进行
  • 也不要使用整数,使用int
  • 这是一个不同的问题。请提出一个新问题。
  • @JensSchauder,完成。 stackoverflow.com/q/18041568/134387

标签: java multithreading synchronization


【解决方案1】:

您不断地创建新的 Integer 对象,然后在其上进行同步,这至少使思考它变得非常混乱。所以可以得到如下场景:

线程 A 获取nRequests 的当前值(假设为 0)

线程 B 排队等待相同的值 (0)

线程A增加nRequests(到值1)

线程 C 获取新值并对其进行同步,增加它并释放该值。

线程 A 放开 0 上的监视器

线程B在0上同步并增加到1,覆盖C的变化

使用第二种方法,您有一个每个人都必须同步的对象。这正是您想要的。

【讨论】:

    【解决方案2】:

    Integer 的实例是不可变的,nRequests++ 因此创建一个新的Integer 对象来保存结果,并将其存储在nRequests 中。 synchronized 语句在对象上同步。因此,线程将在不同的对象上同步。是的,同一对象的同步块中可能只有一个线程,但不同的线程可能同时在不同对象的同步块中……

    同步访问静态的最简单方法是将其放入静态同步方法中:

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

    这相当于下面的同步块:

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

    其中 RequestObject 是包含静态字段的类。

    【讨论】:

      【解决方案3】:

      问题是Integer 类在java 中是不可变的。所以每个线程都在不同的对象上同步,因为nRequests++ 在每次调用时都会创建一个新对象。

      在第二种情况下,lock 对象对于每个实例都是相同的,并成功地将线程的访问序列化为 nRequests 变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-05
        • 1970-01-01
        • 2016-11-24
        • 1970-01-01
        • 1970-01-01
        • 2011-02-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多