欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

volatile关键字的特性及证明

程序员文章站 2022-07-11 08:07:19
volatile是java虚拟机提供的轻量级的同步机制 JMM(Java内存模型)是围绕着并发编程中原子性、可见性、有序性这三个特征来建立的 原子性:一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行。 可见性:当多个线程同时访问同一个变量时,一个线程修改了这个变量的值,其他线程能够 ......

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。