volatile关键字的特性及证明

volatile是java虚拟机提供的轻量级的同步机制

JMM(Java内存模型)是围绕着并发编程中原子性、可见性、有序性这三个特征来建立的

原子性:一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行。

可见性:当多个线程同时访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

有序性:程序执行的顺序按照代码的先后顺序执行。

 

volatile保证了可见性,有序性,不保证原子性

 

证明可见性的代码:

 1 package concurrent;
 2 
 3 import java.util.concurrent.TimeUnit;
 4 
 5 /*
 6  * @description: volatile特性
 7  * @date 2019.04.22 20:48
 8  */
 9 //数据类
10 class Mydata{
11 
12     volatile int num = 0;
13 
14     public void changeNum(){
15         this.num = 100;
16     }
17 }
18 
19 public class VolatileDemo {
20 
21     public static void main(String[] args)  throws InterruptedException{
22         Mydata mydata = new Mydata();
23         new Thread(() -> {
24             System.out.println("===="+Thread.currentThread().getName() +"线程启动===");
25             //暂停3秒
26             try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {}
27             //3秒后t1线程改变num的值
28             mydata.changeNum();
29             System.out.println(Thread.currentThread().getName()+"线程将num的值改为"+mydata.num);
30         },"t1").start();
31 
32         //num的值不变就一直循环
33         long begin = System.currentTimeMillis();
34         while (mydata.num == 0){
35             //num如果不被volatile修饰会一直循环
36         }
37         long cost = System.currentTimeMillis() - begin;
38         System.out.printf(Thread.currentThread().getName()+"线程检测到num的值已经改变,cost{%d},证明了volatile的可见性",cost);
39     }
40 }

运行结果为:

====t1线程启动===
t1线程将num的值改为100
main线程检测到num的值已经改变,cost{3001},证明了volatile的可见性

  

证明不保证原子性的代码:

class Mydata{

    volatile int num = 0;

    public void changeNum(){
        this.num = 100;
    }

    public void numIncreOne(){
        this.num++;
    }
}

public class VolatileDemo {
    
    public static void main(String[] args)  throws InterruptedException{

        Mydata mydata = new Mydata();
        //开启10个线程每个线程调用1000次num++
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    mydata.numIncreOne();
                }
            },String.valueOf(i)).start();
        }

        //输出num的值,如果volatile能保证原子性num将等于10000
        System.out.println(mydata.num);
        System.out.println(mydata.num ==10000?"volatile可以保证原子性":"volatile无法保证原子性");
    }
}

输出结果:

5856
volatile无法保证原子性

 

多线程环境中,线程交替执行,编译器会通过对指定进行重排序来进行优化。被volatile修饰的变量不会参与重排序,保证有序性。

证明有序性的代码:

 1     int num = 0;
 2 
 3     private boolean flag = false;
 4     
 5     private void reSort1(){
 6         num = 1;    //语句1
 7         flag = true; //语句2
 8     }
 9 
10     private void reSort2(){
11         if(flag){
12             num++;
13             System.out.println("num的值为"+num);
14         }
15     }
多线程情况下有可能先执行语句2,再执行语句1,从而导致num只自增1次,输出为1。

 

posted @ 2019-04-22 22:46  有梦想的人不睡觉s  阅读(1185)  评论(0编辑  收藏  举报