Volatile 原理七:volatile 都不保证原子性,为啥我们还要用它
volatile 都不保证原子性,为啥我们还要用它?
奇怪的是,volatile 都不保证原子性,为啥我们还要用它?
volatile 是轻量级的同步机制,对性能的影响比 synchronized 小。
典型的用法:检查某个状态标记以判断是否退出循环。
比如线程试图通过类似于数绵羊的传统方法进入休眠状态,为了使这个示例能正确执行,asleep 必须为 volatile 变量。否则,当 asleep 被另一个线程修改时,执行判断的线程却发现不了。
那为什么我们不直接用 synchorized,lock 锁?它们既可以保证可见性,又可以保证原子性为何不用呢?
因为 synchorized 和 lock 是排他锁(悲观锁),如果有多个线程需要访问这个变量,将会发生竞争,只有一个线程可以访问这个变量,其他线程被阻塞了,会影响程序的性能。
注意:当且仅当满足以下所有条件时,才应该用 volatile 变量
对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
该变量不会与其他的状态一起纳入不变性条件中。
在访问变量时不需要加锁。
volatile 常见应用
这里举一个应用,双重检测锁定的单例模式
代码看起来没有问题,但是 instance = new VolatileSingleton();
其实可以看作三条伪代码:
步骤 2 和 步骤 3 之间不存在 数据依赖关系,而且无论重排前 还是重排后,程序的执行结果在单线程中并没有改变,因此这种重排优化是允许的。
如果另外一个线程执行:if(instance == null)
时,则返回刚刚分配的内存地址,但是对象还没有初始化完成,拿到的 instance 是个假的。如下图所示:
解决方案:定义 instance 为 volatile 变量
版权声明: 本文为 InfoQ 作者【悟空聊架构】的原创文章。
原文链接:【http://xie.infoq.cn/article/9ef0d96919c609cd8a994d3e7】。未经作者许可,禁止转载。
评论