在原子变量上使用 volatile

发布于 2024-09-17 18:07:16 字数 1249 浏览 10 评论 0原文

在变量上使用 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());
    }
} 

Using volatile on a variable reduces the risk of memory consistency error (Please correct me if this reveals some holes in my understanding of any relevant concept). So in the following example even though the variable c1 is volatile, still the occurrence of memory constancy error results in c1 becoming 15 or sometimes 14 in the output rather then the correct output 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());
    }
} 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一抹苦笑 2024-09-24 18:07:16

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

对于此类情况,请考虑使用 AtomicInteger。

You are correct. Because ++ is NOT an atomic operation you can still get inconsistent results where a thread reads/increments/writes a value at the same time as another thread.

Consider using AtomicInteger for cases like this.

北恋 2024-09-24 18:07:16

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

Atomicity is only part of the picture. There is also visibility. If a non-volatile (and non-synchronized) variable value is changed, other threads are not guaranteed to see the change in time, or at all.

铁轨上的流浪者 2024-09-24 18:07:16

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

Check http://www.javabeat.net/tips/169-volatile-keyword-in-java.html for understanding what volatile does. It avoids the intermediate thread cache but anyway there can be the lossed update from reading its value and updating in a non atomic operation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文