JAVA并发编程:volatile的使用及其原理

Posted 一叶一落秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA并发编程:volatile的使用及其原理相关的知识,希望对你有一定的参考价值。

一、volatile的使用

 1、防止重排序

  • 在并发环境下实现单例模式,我们通常可以采用双重检查加锁(DCL)的方式来现实:
    public class Singleton {
    
        public static volatile Singleton singleton;
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            if(singleton == null) {
                synchronized (singleton) {
                    if(singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }

    实例化一个对象其实可以分为三个步骤:

(1)分配内存空间

(2)初始化对象

(3)将内存空间的地址赋值给对应的引用。

但是由于操作系统可以对指令进行重排序,所以上面的过程也可能变成如下过程:

(1)分配内存空间

(2)将内存空间的地址赋值给对应的引用。

(3)初始化对象

如果这是个流程,多线程环境下就可能将一个未初始化的对象引用暴露出来,从而导致不可预料的结果。因此,为了防止这个过程的重排序,我们需要将变量设置为volatile类型的变量。

2、实现可见性

  • 可见性问题主要指一个线程修改了共享变量值,而另一个线程却看不到。引起可见性问题的主要原因就是每个线程拥有自己的高速缓存区——线程工作内存。volatile关键字能有效解决这个问题。
    public class VolatileTest {
    
        int a = 1;
        int b = 2;
    
        public void change() {
            a = 3;
            b = a;
        }
    
        public void print() {
            System.out.println("b=" + b + ";a=" + a);
        }
    
        public static void main() {
            final VolatileTest bean = new VolatileTest();
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    bean.change();
                }
            }).start();
    
    
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    bean.print();
                }
            }).start();
        }
    
        public static void main(String[] args) {
            for(int i = 0; i < 10; i++) {
                main();
            }
        }
    }

 直观上说,这段代码的结果只可能有两种:b=3;a=3或者b=2;a=1。不过运行上面的代码,却出现了三种情况:

 

 

 

以上是关于JAVA并发编程:volatile的使用及其原理的主要内容,如果未能解决你的问题,请参考以下文章

Java 并发编程:volatile的使用及其原理

Java并发编程:Synchronized及其实现原理

Java并发编程:Synchronized及其实现原理

Java并发编程:Synchronized及其实现原理

java多线程

深入理解java:2.1. volatile的使用及其原理