volatile关键字的特性及证明
2019-04-25 06:52:50来源:博客园 阅读 ()
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。
原文链接:https://www.cnblogs.com/dream2true/p/10753625.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring Boot 2.3.0 新特性Redis 拓扑动态感应 2020-06-11
- 今天来介绍java 各版本的新特性,一篇文章让你了解 2020-06-10
- Spring Boot 2.3 新特性优雅停机详解 2020-06-08
- 原创 Spring Boot 2.3 新特性分层JAR 2020-06-08
- 面试官:兄弟,说说Java的static关键字吧 2020-06-04
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash