当前位置: 移动技术网 > IT编程>开发语言>Java > volatile关键字的特性及证明

volatile关键字的特性及证明

2019年04月23日  | 移动技术网IT编程  | 我要评论
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。

 

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网