并发编程的三大性质

public class OrderDemo {

    private static int a = 0, b = 0;
    private static int x = 0, y = 0;

    public static void main(String[] args) throws InterruptedException {
        int i = 0;
        for (;;) {
            i++;
            a = 0;
            b = 0;
            x = 0;
            y = 0;
            CountDownLatch countDownLatch = new CountDownLatch(1);

            Thread thread1 = new Thread(() -> {
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                }
                a = 1;
                x = b;
            });

            Thread thread2 = new Thread(() -> {
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                }
                b = 1;
                y = a;
            });
            thread1.start();
            thread2.start();
            countDownLatch.countDown();
            thread1.join();
            thread2.join();

            String result = "第" + i + "次结果:(" + x + "," + y + ")";
            if (x == 0 && y == 0) {
                System.err.println(result);
                break;
            } else {
                System.out.println(result);
            }
        }
    }
}
……
第570次结果:(0,1)
第571次结果:(0,1)
第572次结果:(0,1)
第573次结果:(0,1)
第574次结果:(0,1)
第575次结果:(0,1)
第576次结果:(0,1)
第577次结果:(0,1)
第578次结果:(0,1)
第579次结果:(0,0)
1 有序性

为提高程序性能,编译器和CPU可能会对没有依赖关系的数据操作进行重排序。
在单线程环境下,重排序不会改变程序的运行结果。
在上面这个例子中,“a = 1”和“x = b”可以交换顺序,“b = 1”和“y = a”可以交换顺序,这样就有可能出现“x == 0 && y == 0”的情况。

2 可见性

在java中,所有共享变量都位于主内存中,各个线程有着属于自己的本地内存。各个线程通过本地内存和主内存进行交互实现对共享数据的读写。一个线程更新共享变量时,如果只将数据写入本地内存,没有及时将本地内存中的数据刷新到主内存,那么其它线程读取共享变量时读取到的是一个过期数值。
在上面这个例子中,线程1更新了a的数值,没有及时将a的数值刷新到主内存,线程2更新了b的数值,没有及时将b的数值刷新到主内存,这样就有可能出现“x == 0 && y == 0”的情况。

3 原子性

在java中,原子操作是指不会被线程调度机制中断的操作。从原子操作开始到原子操作结束,不会发生线程切换。

你可能感兴趣的:(并发编程的三大性质)