【问题标题】:using volatile on atomic variables在原子变量上使用 volatile
【发布时间】:2010-09-03 13:28:27
【问题描述】:

在变量上使用 volatile 可降低内存一致性错误的风险(如果这揭示了我对任何相关概念的理解存在一些漏洞,请纠正我)。所以在下面的例子中,即使变量 c1 是易失性的,内存恒常性错误的发生仍然会导致 c1 在输出中变为 15 或有时为 14,而不是正确的输出 16。

class Lunch implements Runnable {

    private volatile long c1 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    public void inc1() {
       // synchronized(lock1) { c1 is volatile
            c1++;
       // }
    }

    public void run() {
        try {
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
        }
        catch(InterruptedException e) {
            return;
        }
    }
    public long value() {
        return c1;
    }
    public static void main(String args[]) throws InterruptedException {
        Lunch l = new Lunch();
       Thread t1 = new Thread(l);
       Thread t2 = new Thread(l);
       t1.start();
       t2.start();
       t1.join();
       t2.join();
       System.out.println(l.value());
    }
} 

【问题讨论】:

  • 这里的假设是 ++ 是原子的。验证你的假设!
  • (我有点担心你使用“降低风险”这个词。通常的目的是确保完全没有风险。)

标签: java multithreading concurrency volatile


【解决方案1】:

你是对的。因为 ++ 不是原子操作,当一个线程与另一个线程同时读取/递增/写入值时,您仍然会得到不一致的结果。

考虑在这种情况下使用 AtomicInteger。

【讨论】:

  • 因此,如果我将 run() 中对 increment() 的多次调用替换为另一个函数 update(long c1) { this.c1 = c1 },它是此类的一部分。那么既然c1是volatile,不涉及++,那么结果应该是一致正确的吧?
  • AtomicIntegerUpdater 在负载操作存储操作很少的某些情况下。
  • @msk 这将是“正确的”,因为在任何时间点,任何读取 c1 的线程都可以保证看到 c1 的最新值。未经事先检查而设置的信息的有用性通常是值得怀疑的。通常的用例是一个布尔标志,其中一个线程正在向另一个线程发出信号(如停止标志)。这几乎是我使用 volatile 的唯一情况。
【解决方案2】:

原子性只是图片的一部分。还有可见性。如果非易失性(和非同步)变量值发生更改,则无法保证其他线程及时看到更改,或者根本无法看到更改。

【讨论】:

    【解决方案3】:

    查看http://www.javabeat.net/tips/169-volatile-keyword-in-java.html 了解 volatile 的作用。它避免了中间线程缓存,但无论如何读取其值并在非原子操作中更新可能会丢失更新。

    【讨论】:

      猜你喜欢
      • 2012-10-03
      • 1970-01-01
      • 2011-06-25
      • 2015-08-06
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-20
      相关资源
      最近更新 更多