Java volatile关键字实例
来源:互联网 发布:知乎成都旅游 编辑:程序博客网 时间:2024/06/01 13:10
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。
volatile关键字能保证可见性和有序性,但是不保证原子性。因此并不能保证线程安全。
看一个相关的例子:双重校验锁实现的单例模式:
public class DoubleCheckSymbol { private static volatile DoubleCheckSymbol d; private DoubleCheckSymbol() {} public static DoubleCheckSymbol getSymbol() { if (d == null) { synchronized(DoubleCheckSymbol.class) { if (d == null) { d = new DoubleCheckSymbol(); } } } return d; }}
这个单例模式中为什么要加volatile关键字呢?
如果不加volatile的话,会有如下隐患:
d = new DoubleCheckSymbol()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
1, 给d分配内存。
2, 调用 DoubleCheckSymbol的构造函数来初始化成员变量。
3, 将d对象指向分配的内存空间(执行完这步 d就为非 null 了)。
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,但是由于它并未初始化,所以就可能发生错误。
此例中,synchronized关键字已经解决了原子性问题。同时也解决了可见性问题,因为synchronized能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。
然而有序性问题并没有解决,所以,这就是在这里使用volatile的目的,即为了防止指令顺序的重排序。
另外,如果在JDK1.5之前这样用volatile的话,可能会出现异常结果。此前的JDK中即使将变量声明为volatile也不能完全避免重排序导致的问题(主要是volatile变量前后的代码仍然存在重排序问题)。
再看一个例子:
package com.lwc.test;import java.util.concurrent.CountDownLatch;public class Counter { private static volatile int value; private static CountDownLatch countDownLatch = new CountDownLatch(10000); public static void main(String[] args) throws Exception{ for (int i=0;i<10000;i++){ new Thread(){ @Override public void run() { increment(); countDownLatch.countDown(); } } .start(); } countDownLatch.await(); System.out.println(getValue()); } public static int increment(){ return value ++; } public static int getValue(){ return value; }}
输出:可能是10000,也可能是小于10000的数,同样是因为volatile不能保证原子性(value ++并不是原子性操作,所以会出现两个线程同时取得了相同的value值,然后分别+1,然后各自写入内存,结果value只增加了1的情况)。
更详细的解释,可以参考前人总结:
http://www.cnblogs.com/dolphin0520/p/3920373.html
- Java volatile关键字实例
- java 关键字volatile
- Java中的volatile关键字
- Java中的volatile关键字
- JAVA:volatile关键字
- Volatile 关键字 java
- Java中的volatile关键字
- Java线程:volatile关键字
- Java线程:volatile关键字
- Java中的volatile关键字
- Java线程:volatile关键字
- Java中的volatile关键字
- Java线程:volatile关键字
- Java中的volatile关键字
- java的关键字volatile
- Java中的volatile关键字
- Java Volatile 关键字
- 温故而知新:Java volatile 关键字
- 交叉编译Qt5.9.0
- 使用koa-generator生成koa2项目
- 二叉树、B树、B+树、B*树、LSM树
- js三级联动之地域的选择
- eclipse使用与java语法规则
- Java volatile关键字实例
- 采用apt快速搭建lnmp服务
- 本地时间
- Mysql忘记密码怎么办?
- Java 内存模型及GC原理
- Maven项目报错解决方案
- 欢迎使用CSDN-markdown编辑器
- JS之事件委托
- Apache安装错误 APR not found解决方法