Skip to main content

可见性volatile

huhxAbout 1 minjavaThreadConcurrency

可见性

public class VolatileTest {
    private static boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            System.out.println("Thread start, time: " + LocalDateTime.now());
            while (running) {
            }
            System.out.println("Thread end, time: " + LocalDateTime.now());
        }).start();

        TimeUnit.SECONDS.sleep(3);

        running = false;
    }
}

 














输出结果:

Thread start, time: 2023-09-04T11:01:56.216820

一直都没能结束,如果在第二行加上volatile修饰符。那么输出结果如下:

Thread start, time: 2023-09-04T11:03:50.573060
Thread end, time: 2023-09-04T11:03:53.559628

非原子性

public class VolatileTest {
    volatile int count = 0;

    void increment() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        var volatileTest = new VolatileTest();

        var threads = new ArrayList<Thread>();
        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(volatileTest::increment));
        }

        for (Thread thread : threads) thread.start();
        for (Thread thread : threads) thread.join();

        System.out.println(volatileTest.count);
    }
}

输出的结果不确定,但是一般会小于10000

38596

解决办法,可以使用提供CAS功能的AtomicInteger,它既满足原子性要求,还同时拥有可见性。

AtomicInteger count = new AtomicInteger();

void increment() {
    for (int i = 0; i < 10000; i++) {
        count.incrementAndGet();
    }
}

禁止指令重排序

内存读写屏障

指令重排序

FAQ

Lamda表达式里面的异常不能throw?

Long或者Doudble的读写是原子性的吗?

long和double的读写不是原子性的,但是加了volatile就是原子性的。

总结

参考