volatile

volatile的特性

内存可见性:先看两段代码

    public static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (flag) {

            }
            System.out.println("task1----stop");
        });
        t1.start();

        Thread.sleep(100);
        Thread t2 = new Thread(() -> {
            flag = false;
        });
        t2.start();

    }

这段代码执行,thread1,里面有一个while循环,当flag是true的话会一致循环下去,而thread2 负责把flag改成false。然而根据JMMjava内存模型,thread1并不会因为thread2将flag改成false而退出循环。
因为按照JMM的设定, 参考下图的java内存抽象结构示意图,图片源自网络
volatile特性插图

根据上图我们可以看出,线程间的共享数据都存在主存中,每个线程执行的时候,都会拷贝一份变量到线程内存中,所以每个线程间的变量理论上是独立的不共享的,需要共享的时候,需要将数据刷到主存,然后主存在混存到线程内存中去。
这样也就解释了为什么上面会出现thread1死循环无法退出的情况了。

如果我们将Thread1的while修改下,在里面增加一个print方法,如下

        Thread t1 = new Thread(() -> {
            while (flag) {
                System.out.println(111);
            }
            System.out.println("task1----stop");
        });
        t1.start();

这个时候我们在执行程序会发现thread1正常退出了。这说明thread2修改的flag数据thread1拿到了。
网上有一种说法是因为 System.out.println方法是一个用 synchronized
关键字修饰的同步方法。当执行完这个方法以后会释放锁,释放锁的操作会导致该线程重新从主存中读取共享变量的值。(线程释放锁会强制刷写到主存,线程获取锁会强制从主存重新刷新变量值)。
另外如果我们在第一段代码上面while上做断点的话,会会发现本来已经死循环的代码跳出了while循环,也就是本来flag是true的,断点后flag就变成false,而线程的切换会导致线程原本的工作内存中缓存失效,然后去主存重新读取共享变量的值
还有一种说法是说执行线程的CPU在空闲的时候,也会去读取一下主存的共享变量。这也是为什么第一个代码的例子,有一定的概率程序也会跳出死循环的原因。
参考这篇博客 https://blog.csdn.net/w929491852/article/details/108508000

如果用volatile修改flag变量,效果就会不一样了。将第一段代码中的flag变量加上volatile修饰

public volatile static boolean flag = true;

会发现,这时候thread1里面的while就会正常退出了。因为使用volatile修饰的变量内存可见。为什么使用volatile修饰过的变量内存课件,这里需要提到一个概念内存栅栏(内存屏障)
内存栅栏(Memory Barrier)就是从本地或工作内存到主存之间的拷贝动作。
volatile特性插图1
当写操作线程先跨越内存栅栏而读线程后跨越内存栅栏的情况下,写操作线程所做的变更才对其他线程可见。在程序运行过程中,变量先在本线程缓存中更新,然后在跨越屏障更新到主存。所有读操作一定是在写操作跨越屏障后才能跨越屏障读取到更新后的数据(happens-before)。

volatile能否保证原子性?

先看代码

public class SysThread implements Runnable {

    private volatile Integer i = 0;

    public void addMyself() {
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        i++;
        System.out.println(Thread.currentThread().getName() + ".." + i);
    }

    @Override
    public void run() {
        for (int j = 0; j < 1000; j++)
            addMyself();
    }
}

    public static void main(String[] args) {
        SysThread sysMainTest = new SysThread();
        Thread thread1 = new Thread(sysMainTest,"thread1");
        Thread thread2 = new Thread(sysMainTest,"thread2");
        Thread thread3 = new Thread(sysMainTest,"thread3");
        Thread thread4 = new Thread(sysMainTest,"thread4");
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }

执行结果我们可以看到以下一段结果:

...
hread1..3467
thread3..3468
thread2..3467
thread2..3470
thread1..3470
thread4..3470
thread3..3470
thread2..3471
thread4..3474
thread1..3472
...

从这个结果我们可以看到,volatile并不具备原子性,
也是使用volatile注意的一个地方: volatile修饰的变量的值的更改不能依赖于前值,除非你加锁,可是使用synchronized锁住方法或代码块,或者使用atomic类。这里不介绍这个

669 对 “volatile特性”的想法;

  1. Dünyanın en büyük borsalarından biri olan binance için binance güvenilir mi sorusunu soran ziyaretçilerimizi web
    sayfamıza bekleriz. Sizler de dünyanın en büyük borsalarından biri olan binancenin güvenilir
    olup olmadığını merak ediyorsanız binance güvenilir mi yazımız aracılığı
    ile bunu hemen öğrenebilirsiniz.

    binance güvenilir mi

  2. Son zamanların en iyi Türk borsalarından biri olan Paribu güvenilir mi diye merak ediyorsanız tek yapmanız gereken hemen tıklamak ve paribu güvenilir
    mi sorusuna yanıt bulmak. Tıklayın ve paribu güvenilir mi hemen öğrenin. Sizler için paribu güvenilir mi
    sorusunun yanıtı burada.

    paribu güvenilir mi

  3. Sitemiz üzerinden o günün en çok okunan ilahi sözlerine erişebilir eriştiğiniz ilahi sözünü değerli arkadaşlarınız ile paylaşabilirsiniz.
    Bugünün en çok okunan ilahisi sevdim seni mabuduma sözleri Her gün güncel olarak sizlerin hoşunuza gidebilecek içinizi rahatlatıcak ilahilerin sözlerini paylaşıyoruz.

    Bunların yanı sıra güncellenen ilahi arşivimiz ile
    sizlere 7/24 websitemiz üzerinden ilahi sözleri hizmeti veriyoruz.
    Türkiye’nin en büyük ilahi sözleri sitesi olmanın gururunu yaşıyoruz.

    ilahi sözleri