volatile关键字及内存可见性
2017-01-22 22:14
253 查看
先看一段代码:
运行这段代码,运行的结果只有:
flag= true
这是由于 子线程在操作共享数据时,会将主存总的flag,复制一份到线程的缓存中进行操作,操作完成后会再将数据写到主存中,由于while(true)是一个运行效率非常高的一句代码,而且运行速度非常快,导致主线程再执行循环时没有机会从主存中读取到数据,导致flag的值是主线程最初读到的值,flag = false;
在共享变量上加一个volatile关键字,会解决这个问题
----------------
flag= true
volatile 关键字的作用:当多个线程操作共享数据时,可以保证内存中的数据是可见的。
可以使用内存再来解释,可以认为各个线程操作各自独立缓存中的数据是实时与主存进行同步的,可以理解为多个线程直接在主存中操作数据,而不是在各自的缓存中。
加了volatile后性能还是比什么都不加要讲的,但是比锁的效率要高。
加了volatile之后效率会低在哪?
实际上JVM底层有个优化,叫指令重排序,使用volatile修饰后就不能重排序了。
加锁的效率是最低的(使用synchronized关键字),同步锁会使线程每次从主存中读取数据,但是同步锁的效率很低。有多个线程来访问时先判断锁,如果被其他线程锁挡住,则线程会进入阻塞挂起状态,那得等到下次cpu再次分配任务,才能执行。
当然:volatile和synchronized还是不同的。volatile相较与synchronized是一种较为轻量级的同步策略。
注意:
1. volatile 不具备 "互斥性"
2. volatile 不能保证变量的 "原子性"
package com.java.juc; public class TestVolatile { public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); new Thread(td).start(); while(true){ if(td.isFlag()){ System.out.println("----------------"); break; } } } } class ThreadDemo implements Runnable{ private boolean flag = false; public void run() { try { Thread.sleep(200); flag = true; System.out.println("flag= "+ isFlag()); } catch (InterruptedException e) { e.printStackTrace(); } } /** * @return the flag */ public boolean isFlag() { return flag; } /** * @param flag the flag to set */ public void setFlag(boolean flag) { this.flag = flag; } }
运行这段代码,运行的结果只有:
flag= true
这是由于 子线程在操作共享数据时,会将主存总的flag,复制一份到线程的缓存中进行操作,操作完成后会再将数据写到主存中,由于while(true)是一个运行效率非常高的一句代码,而且运行速度非常快,导致主线程再执行循环时没有机会从主存中读取到数据,导致flag的值是主线程最初读到的值,flag = false;
在共享变量上加一个volatile关键字,会解决这个问题
package com.java.juc; public class TestVolatile { public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); new Thread(td).start(); while(true){ if(td.isFlag()){ System.out.println("----------------"); break; } } } } class ThreadDemo implements Runnable{ private volatile boolean flag = false; public void run() { try { Thread.sleep(200); flag = true; System.out.println("flag= "+ isFlag()); } catch (InterruptedException e) { e.printStackTrace(); } } /** * @return the flag */ public boolean isFlag() { return flag; } /** * @param flag the flag to set */ public void setFlag(boolean flag) { this.flag = flag; } }
----------------
flag= true
volatile 关键字的作用:当多个线程操作共享数据时,可以保证内存中的数据是可见的。
可以使用内存再来解释,可以认为各个线程操作各自独立缓存中的数据是实时与主存进行同步的,可以理解为多个线程直接在主存中操作数据,而不是在各自的缓存中。
加了volatile后性能还是比什么都不加要讲的,但是比锁的效率要高。
加了volatile之后效率会低在哪?
实际上JVM底层有个优化,叫指令重排序,使用volatile修饰后就不能重排序了。
加锁的效率是最低的(使用synchronized关键字),同步锁会使线程每次从主存中读取数据,但是同步锁的效率很低。有多个线程来访问时先判断锁,如果被其他线程锁挡住,则线程会进入阻塞挂起状态,那得等到下次cpu再次分配任务,才能执行。
当然:volatile和synchronized还是不同的。volatile相较与synchronized是一种较为轻量级的同步策略。
注意:
1. volatile 不具备 "互斥性"
2. volatile 不能保证变量的 "原子性"
相关文章推荐
- PHP MVC 小实例
- linux下安装subversion1.9.5
- Linux&C语言文件学习笔记(四):文件I/O与系统API续
- 浅析Spring的JdbcTemplate
- 手动实现Spring Aop
- CentOS6.x 安装升级Python2.7.x Python3.4.x
- 祝吴祖基老师100岁
- 简单编程题目连载(十)——公共最长子序列
- C#常用函数
- javascript中对数据文本格式化的思考
- ssm框架搭建(上)
- JDK源码(1.7) -- java.util.Collection<E>
- Glide进阶详解(十)
- Py第十九问 Your local changes would be overwritten by merge. Commit, stash or revert them to proceed.
- Oracle使用强制索引注意事项
- Two pointers (5) -- Remove Duplicates from Sorted Array I, II, Move Zeroes, Remove Element
- 屏幕适配图片
- Hibernate中的Session对象
- JavaSE 学习参考:算术运算符
- POJ2155 Matrix