033 内存可见性和volatile关键词

一 . JVM内存结构

  

在上图之中,我们可以注意到JVM为了加快运行,使用了缓存机制,但是在使用了缓存机制之后,就会出现缓存的不一致性的问题.

下面演示一个代码:

public class VolatileTest {

    private Boolean flag = true;

    public static void main(String[] args) {
        VolatileTest demo = new VolatileTest();

        new Thread(() -> {
            for (;;) {
                if (!demo.flag) {
                    System.out.println("end..");
                    return;
                }
            }
        }).start();

        new Thread(() -> {

            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            demo.flag = false;
        }).start();

    }
}

上面的代码之中,我们期望在运行之后,我们设置的符号标记被修改掉,通过这样的方式,我们就能完成对第一个线程的停止.

但是结果出乎我们的意料,第一个线程永远不会终结.


二 .可见性

造成层上面的问题的根源就是JVM的缓存机制导致的,第一个线程使用的是一个线程栈之中的副本,而这个副本永远都是true,因此我们上面的方式时永远不能停止线程的.

可见性问题:
  在多线程并发的情况下,由于JVM的缓存机制造成缓存之间的不同步,(一个线程对一个变量进行了修改,但是另外的线程无法及时的知晓),这就是可见性问题.


三 . 可见性问题的解决

  既然可见性的问题就是缓存不一致性引发出来的,因此我们只需要一个缓存同步的方法就能解决这个问题.

在java之中,出现了volatile关键词,这个关键词帮助实现了对被volatile关键词修饰的变量一旦进行了修改,那么其他的线程一定会得到通知,从主存之中获取新的数据.

通过这种方式,就解决了可见性问题.


四 .轻量级同步方式

  通过上面的介绍,我们可以看出volatile是一个轻量级的同步工具,帮助我们解决了线程安全性问题.

  也就是说,可见性问题也是一种引起线程安全性问题的原因.

在这里我们可以看到,解决线程安全性问题的方式:

[1]原子性:

[2]可见性:

[3]有序性: 使用volatile也能解决一定的有序性.

原文地址:https://www.cnblogs.com/trekxu/p/9843217.html