java - 为什么 volatile 不能解决比较过程中的数据争用问题

标签 java multithreading volatile

我正在尝试使用多线程并遵循此处的示例:https://docs.oracle.com/javase/specs/jls/se10/html/jls-8.html#jls-8.3.1.4

我已在下面发布了我的代码。 您能否帮助我理解为什么“if (x < y) { ”而不是“if (y > x) { ”发生数据争用?

我正在使用openjdk-14.0.1:

Linux void-MS-7678 5.4.0-29-generic #33-Ubuntu SMP Wed Apr 29 14:32:27 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

代码:

public class Main {
    public static void main(String[] args) {
        DataRace dr = new DataRace();
        Thread t1 = new Thread(()-> {
            for (int i = 0; i < 100_000; i++) {
                dr.increment();
            }
        });

        Thread t2 = new Thread(()-> {
            for (int i = 0; i < 100_000; i++) {
                dr.check();
            }
        });

        t1.start();
        t2.start();
    }

    private static class DataRace {
        private volatile int x = 0, y = 0;

        public void increment() {
            x++;
            y++;
        }

        public void check() {
            // System.out.println("x=" + x + " y="+ y); // - NO ISSUES
            // if (y > x) { - NO ISSUES
            // if (x < y) { - ISSUES
            if (x < y) {
                System.out.println("DataRace detected: x < y");
            }
        }
    }
}

输出:

/home/void/.jdks/openjdk-14.0.1/bin/java -javaagent:/home/void/Development/idea-IC-183.4588.61/lib/idea_rt.jar=46411:/home/void/Development/idea-IC-183.4588.61/bin -Dfile.encoding=UTF-8 -classpath /home/void/Development/multithreading/out/production/classes Main
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y
DataRace detected: x < y

Process finished with exit code 0

最佳答案

比较if (x < y) {不是原子的。

  • t2负载x用于比较
  • t2停止工作
  • t1增量xy
  • t1停止
  • t2开始
  • t2负载y用于比较
  • x是旧值并且 y是新的,递增的,x < ytrue .

以下是如何使用 synchronized 解决该问题的示例:

class Main {
    public static void main(String[] args) {
        DataRace dr = new DataRace();
        Thread t1 = new Thread(()-> {
            for (int i = 0; i < 100_000; i++) {
                dr.increment();
            }
        });

        Thread t2 = new Thread(()-> {
            for (int i = 0; i < 100_000; i++) {
                dr.check();
            }
        });

        t1.start();
        t2.start();
    }

    private static class DataRace {
        private volatile int x = 0, y = 0;

        public synchronized void increment() {
            x++;
            y++;
        }

        public void check() {
            // System.out.println("x=" + x + " y="+ y); // - NO ISSUES
            // if (y > x) { - NO ISSUES
            // if (x < y) { - ISSUES
            boolean xSmallerY = false;
            synchronized (this) {
                xSmallerY = x < y;
            }
            if (xSmallerY) {
                System.out.println("DataRace detected: x < y");
            }
        }
    }
}

关于java - 为什么 volatile 不能解决比较过程中的数据争用问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61648172/

相关文章:

java - 如何让线程等到数组包含元素

c - 赋值表达式和 volatile

java volatile与java链表一起使用

c# - 有助于在 C# 中学习多线程的练习建议

java - 线程的顺序执行卡住

java - 使用 libphonenumber 时使用 Iterator.next() 获取 java.util.NoSuchElementException

java - 在 Java 中创建 JSON 对象

java - 这个二维数组可以存储多少个整数?

java - GZIPInputStream 和字符集

java - 杀死并清理调用方法的线程?