volatile关键字的特性及证明
程序员文章站
2022-03-20 12:43:46
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。
上一篇: 没有梦想的好处