Java多线程之内存可见性——volatile
来源:互联网 发布:淘宝网,挂烫机加热器 编辑:程序博客网 时间:2024/06/15 02:14
volatile关键字:
1.能够保证volatile变量的可见性
2.不能保证volatile变量的复合操作的原子性
volatile是通过加入内存屏障和禁止重排序优化来实现内存可见性。
java中具体的屏障指令就不说了,可以自行搜索
通俗来说:
volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,
而当该变量发生变化时,又会强迫线程将线程将最新的值刷新到主内存。
这样任何时刻,不同的线程总能看到该变量的最新值。
那么volatile的读写操作的过程:
线程写volatile变量的过程:
1.改变线程工作内存中volatile变量的副本的值
2.将改变后的副本的值从工作内存刷新到主内存
线程读volatile变量的过程:
1.从主内存中读取volatile变量的最新值到线程的工作内存中
2.从工作内存中读取volatile变量的副本
public class Demo { //由于volatile不具备原子性(同步),所以代码运行中出现小于500的情况 private volatile int number = 0; public int getNumber() { return this.number; } public void increase() { try { Thread.sleep(100); //休眠是为了使实验结果更明显 } catch(InterruptedException e) { e.printStackTrace(); } this.number++; } public static void main(String args[]) { final Demo demo = new Demo(); for(int i=0;i<500;i++) { new Thread(new Runnable() { //覆写run方法 public void run() { Demo.increase(); } }).start(); } //如果子线程都运行完了,主线程再继续往下执行 while(Thread.activeCount() > 1) { //判断是否500个子线程是否执行完 Thread.yield(); } System.out.println("number:"+Demo.getNumber()); }}/*简要分析:当number为100时,1.线程A读取number的值2.线程B读取number的值3.线程B执行加1操作4.线程B写入最新的number的值5.线程A执行加1操作6.线程A写入最新的number的值不难发现,两次number++只增加了1,这就是原因所在*/
解决方案即为保证变量的原子性即可:
1.使用synchronized关键字
2.使用ReentrantLock(java.util.concurrent.locks包下)
3.使用AtomicInteger(vava.util.concurrent.atomic包下)
解决代码:
//第一种方案,在numbe++加synchronized关键字public void increase() { try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } synchronized(this) { //缩小锁粒度,没必要锁整个方法 this.number++; }}
//第二种方案,使用lock锁import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Demo { //锁操作还是很强的,感兴趣可以深入了解下 private Lock lock = new ReentrantLock; private int number = 0; public int getNumber() { return this.number; } public void increase() { try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } //这里的加锁解锁,相当于进入退出synchronized代码块 //同时也可以保证number的可见性,number++的原子性 lock.lock(); try { //之所以加入try语句,是因为锁内部的操作可能会抛出异常 this.number++; } finally { lock.unlock(); } } //mian方法不变}
volatile使用的场合 :
1.对变量的写入操作不依赖其当前值
不满足:number++等依赖前一个数的值 等等
满足:boolean变量,记录温度变化的变量 等等2.该变量没有包含在具有其他变量的不变式中
不满足:不变式 low < up 等
0 0
- Java多线程之内存可见性——volatile
- Java多线程之内存可见性——synchronized与volatile比较
- java多线程之内存可见性-synchronized、volatile
- java多线程之内存可见性-synchronized、volatile
- Java多线程之内存可见性——synchronized
- volatile之内存可见性
- Java多线程之内存可见性
- Java多线程之内存可见性
- JAVA多线程之内存可见性笔记
- Java多线程之内存可见性
- Java多线程之内存可见性
- Java多线程之内存可见性
- 浅谈java多线程之内存可见性
- Java多线程之内存可见性
- Java多线程之内存可见性
- Java多线程之内存可见性
- Java多线程之内存可见性
- java多线程之内存可见性
- 1001. A+B Format (20)
- 安卓图片的压缩,尺寸,质量,采样率和微信压缩
- redhat 6 使用centos源 yum安装
- 2017的开端,导入工程到AS需要修改的文件
- Smarty基本配置与使用
- Java多线程之内存可见性——volatile
- C#项目如何做好源码保护?
- centos6.5 bind-DNS服务器bind的搭建详解
- 数组
- RHEL 6.3使用CentOS yum源 (redhat yum安装失败)
- 阿里云linux
- kali linux 2016 安装和使用指南
- MapReduce中Combiner的作用和用法
- Debugger and device times had drifted by more than 60s. Please correct this by running adb shell "da