Java内存模型以及volatile关键字详解
2019-08-31 07:23:12来源:博客园 阅读 ()
Java内存模型以及volatile关键字详解
在讲解Java内存模型之前给大家看一个栗子。1 package com.company; 2 4 public class VolatileVisibilityTest { 5 private static boolean initFlag=false; 6 public static void main(String[] args) throws InterruptedException { 7 new Thread(new Runnable() { 8 @Override 9 public void run() { 10 System.out.println("waiting data..."); 11 while (!initFlag) { 12 } 13 System.out.println("Success"); 14 } 15 }).start(); 16 18 Thread.sleep(2000, 0); 19 20 21 new Thread(new Runnable() { 22 @Override 23 public void run() { 24 prepareData(); 25 } 26 }).start(); 27 } 28 public static void prepareData(){ 29 System.out.println("preparing data..."); 30 initFlag=true; 31 System.out.println("prepare end..."); 32 } 33 }
大家可能会认为出现下面的结果:
waiting data...
preparing data...
prepare end...
Success
结果真的是这样的吗?下面我就启动main方法,演示结果如下
waiting data... preparing data... prepare end...并没有打印出Success,大家可能会奇怪下面的线程已经把initData变量改成了true,上面的线程应该会跳出死循环,打印出Success。 我们搜索csdn查看什么是Java内存模型的原子操作,给出的解释如下,大家一脸懵逼,这说的啥意思:
- read(读取):从主内存读取数据
- load(载入):将主内存读取到的数据写入工作内存
- use(使用):从工作内存读取数据来计算
- assign(赋值):将计算好的值重新赋值到工作内存中
- store(存储):将工作内存数据写入主内存
- write(写入):将store过去的变量值赋值给主内存中的变量
- lock(锁定):将主内存变量加锁,标示为线程独占状态
- unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
- 总线加锁(性能太低)
- MEIS缓存一致性协议
- 会将当前处理器的缓存行的数据立即写回到系统内存。
- 这个写回内存的操作会引起其他cpu里缓存了该内存地址的数据无效(MESI)
- 将hsdis-amd64.dll文件放到你的jre的bin目录下:
-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*VolatileVisibilityTest.prepareData3.执行main方法,代码太多, volatile底层也是加lock锁来实现缓存一致性协议,那么他与总线加锁有什么区别呢? volatile只对内存的缓存行进行加锁,然后进行赋值操作。 并发编程的三大特性:可见性,原子性,有序性 volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronized关键字 如何理解上面这句话的意思呢?下面我再给大家举一个栗子
package com.company; public class VolatileAtomicTest { public static volatile int num=0; public static void increase(){ num++; } public static void main(String[] args) throws InterruptedException { Thread[] threads=new Thread[10]; for (int i = 0; i < threads.length ; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j <1000 ; j++) { increase(); } } }); threads[i].start(); } for(Thread t:threads){ t.join(); } System.out.println(num); } }大家猜一猜,上面的程序运行后的结构是多少呢? 先抢到锁的线程会把没有抢到锁的线程的值失效掉 说完了可见性、原子性,最后我给大家讲一讲有序性
package com.company; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class VolatileSerialTest { static int x=0,y=0; public static void main(String[] args) throws InterruptedException { Set<String> resultSet=new HashSet<>(); Map<String,Integer> resultMap=new HashMap<>(); for (int i = 0; i <10000 ; i++) { x=0;y=0; resultMap.clear(); Thread one =new Thread(new Runnable() { @Override public void run() { int a=y; x=1; resultMap.put("a",a); } }); Thread other =new Thread(new Runnable() { @Override public void run() { int b=x; y=1; resultMap.put("b",b); } }); one.start(); other.start(); one.join(); other.join(); resultSet.add("a="+resultMap.get("a")+","+"b="+resultMap.get("b")); System.out.println(resultSet); } } }
大家想一想,上面输出的结果是多少呢?运行程序,最后会出现四种情况。 大家思考一下,为什么?
原文链接:https://www.cnblogs.com/lubanAllen/p/11438783.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Class文件结构-常量池
下一篇:Class文件结构-属性表
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
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