转自http://www.iteye.com/topic/109150

volatile, 用更低的代价替代同步

为什么 使用volatile比同步代价更低? 
同步的代价, 主要由其覆盖范围决定, 如果可以降低同步的覆盖范围, 则可以大幅提升程序性能.

而volatile的覆盖范围仅仅变量级别的. 因此它的同步代价很低.

volatile原理是什么?
volatile的语义, 其实是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我.(工作内存详见java内存模型)

因此, 当多核或多线程在访问该变量时, 都将直接 操作 主存, 这从本质上, 做到了变量共享.

volatile的有什么优势? 
1, 更大的程序吞吐量
2, 更少的代码实现多线程
3, 程序的伸缩性较好
4, 比较好理解, 无需太高的学习成本

volatile有什么劣势? 
1, 容易出问题
2, 比较难设计

volatile运算存在脏数据问题

volatile仅仅能保证变量可见性, 无法保证原子性.

volatile的race condition示例:

Java代码  
  1. public class TestRaceCondition {
  2. private volatile int i = 0;
  3. public void increase() {
  4. i++;
  5. }
  6. public int getValue() {
  7. return i;
  8. }
  9. }

当多线程执行increase方法时, 是否能保证它的值会是线性递增的呢? 
答案是否定的.

原因:
这里的increase方法, 执行的操作是i++, 即 i = i + 1;
针对i = i + 1, 在多线程中的运算, 本身需要改变i的值.
如果, 在i已从内存中取到最新值, 但未与1进行运算, 此时其他线程已数次将运算结果赋值给i.
则当前线程结束时, 之前的数次运算结果都将被覆盖.

即, 执行100次increase, 可能结果是 < 100.
一般来说, 这种情况需要较高的压力与并发情况下, 才会出现.

如何避免这种情况? 
解决以上问题的方法:
一种是 操作时, 加上同步.
这种方法, 无疑将大大降低程序性能, 且违背了volatile的初衷.

第二种方式是, 使用硬件原语(CAS), 实现非阻塞算法
从CPU原语上, 支持变量级别的低开销同步.

CPU原语-比较并交换(CompareAndSet),实现非阻塞算法

什么是CAS? 
cas是现代CPU提供给并发程序使用的原语操作. 不同的CPU有不同的使用规范.

在 Intel 处理器中,比较并交换通过指令的 cmpxchg 系列实现。
PowerPC 处理器有一对名为“加载并保留”和“条件存储”的指令,它们实现相同的目地;
MIPS 与 PowerPC 处理器相似,除了第一个指令称为“加载链接”。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)

什么是非阻塞算法? 
一个线程的失败或挂起不应该影响其他线程的失败或挂起.这类算法称之为非阻塞(nonblocking)算法

对比阻塞算法:
如果有一类并发操作, 其中一个线程优先得到对象监视器的锁, 当其他线程到达同步边界时, 就会被阻塞.
直到前一个线程释放掉锁后, 才可以继续竞争对象锁.(当然,这里的竞争也可是公平的, 按先来后到的次序)

CAS 原理:

我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

CAS使用示例(jdk 1.5 并发包 AtomicInteger类分析:)

Java代码  
  1. public final int getAndSet(int newValue) {
  2. for (;;) {
  3. int current = get();
  4. if (compareAndSet(current, newValue))
  5. return current;
  6. }
  7. }
  8. public final boolean compareAndSet(int expect, int update) {
  9. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
  10. }

这个方法是, AtomicInteger类的常用方法, 作用是, 将变量设置为指定值, 并返回设置前的值.
它利用了cpu原语compareAndSet来保障值的唯一性.

另, AtomicInteger类中, 其他的实用方法, 也是基于同样的实现方式.
比如 getAndIncrement, getAndDecrement, getAndAdd等等.

CAS语义上存在的 " ABA 问题"

什么是ABA问题?
假设, 第一次读取V地址的A值, 然后通过CAS来判断V地址的值是否仍旧为A, 如果是, 就将B的值写入V地址,覆盖A值.

但是, 语义上, 有一个漏洞, 当第一次读取V的A值, 此时, 内存V的值变为B值, 然后在未执行CAS前, 又变回了A值.
此时, CAS再执行时, 会判断其正确的, 并进行赋值.

这种判断值的方式来断定内存是否被修改过, 针对某些问题, 是不适用的.

为了解决这种问题, jdk 1.5并发包提供了AtomicStampedReference(有标记的原子引用)类, 通过控制变量值的版本来保证CAS正确性.

其实, 大部分通过值的变化来CAS, 已经够用了.

jdk1.5原子包介绍(基于volatile)

包的特色:
1, 普通原子数值类型AtomicInteger, AtomicLong提供一些原子操作的加减运算.

2, 使用了解决脏数据问题的经典模式-"比对后设定", 即 查看主存中数据是否与预期提供的值一致,如果一致,才更新.

3, 使用AtomicReference可以实现对所有对象的原子引用及赋值.包括Double与Float,
但不包括对其的计算.浮点的计算,只能依靠同步关键字或Lock接口来实现了.

4, 对数组元素里的对象,符合以上特点的, 也可采用原子操作.包里提供了一些数组原子操作类
AtomicIntegerArray, AtomicLongArray等等.

5, 大幅度提升系统吞吐量及性能.

具体使用, 详解java doc.

转载于:https://www.cnblogs.com/balaamwe/archive/2011/11/22/2259081.html

volatile原理与技巧相关推荐

  1. 24.volatile关键字的作用、volatile原理、可见性、内存屏障、volatile性能、transient

    24.volatile关键字的作用 24.1.volatile原理 24.2.可见性 24.3.内存屏障 24.4.volatile性能 25.transient 24.volatile关键字的作用 ...

  2. 游戏建模过程中如何布线?建模布线原理和技巧

    很多同学不知道在人物的建模过程中如何布线,导致模型出现很多问题,今天本文就这个问题带个大家一些关于模型布线的原理以及技巧. 1.首先我们得知道布线是建模过程中不可避免的一个东西,关系到后边展UV,刷权 ...

  3. java volatile原理A CUP层面

    作者:知乎用户 链接:https://www.zhihu.com/question/49656589/answer/117826278 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业 ...

  4. 经验 | OpenCV图像旋转的原理与技巧

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自|OpenCV学堂 01 引言 初学图像处理,很多人遇到的 ...

  5. OpenCV图像旋转的原理与技巧

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 转自|OpenCV学堂 01 引言 初学图像处理,很多人遇到的第一 ...

  6. 浅析volatile原理及其使用

    前言 经常在网上看一些大牛们的博客,从中收获到一些东西的同时会产生一种崇拜感,从而萌发了自己写写博客的念头.然而已经有这个念头很久,却始终不敢下手开始写.今天算是迈出了人生的一大步^_^! volat ...

  7. 数据科学的原理与技巧 一、数据科学的生命周期

    一.数据科学的生命周期 原文:DS-100/textbook/notebooks/ch01 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 在数据科学中,我们使用大量不同的数据集 ...

  8. Spring 事务原理篇:@EnableTransactionManagement注解底层原理分析技巧,就算你看不懂源码,也要学会这个技巧!

    前言 学习了关于Spring AOP原理以及事务的基础知识后,今天咱们来聊聊Spring在底层是如何操作事务的.如果阅读到此文章,并且对Spring AOP原理不太了解的话,建议先阅读下本人的这篇文章 ...

  9. linux磁盘管理原理,Linux操作系统中磁盘存储区管理的原理与技巧

    命令篇 下表包含一列最常用的parted命令. print A table similar to the following will appear: Disk geometry for /dev/h ...

最新文章

  1. 2020 年 5 月程序员工资统计,平均 14542 元,我又拖后腿了!
  2. javascript闭包-全局变量与局部变量
  3. 基于TCP的Socket通讯
  4. NOIP2016 D2T3 愤怒的小鸟
  5. 51单片机8*8点阵屏、取模软件的使用
  6. 助力 .NET MAUI Community Toolkit
  7. 全球顶级开源大神们现身 COSCon'20
  8. 跑来跑去:假人与AWS Lambda的第一次接触
  9. Win32ASM学习[21]:宏汇编(1)
  10. 第一步:Axure 使用svn多人协作产品开发(提交文件)
  11. mysql删除盘点表,用友U8数据库表名参照表修改号参考.doc
  12. 在阿里巴巴工作是一种怎样的体验?
  13. 系统无法在此计算机硬件上运行,Windows安装程序无法将配置未在此计算机的硬件上运行的解决方案-太平洋电脑网...
  14. mysql show sleep_mysq解决sleep进程过多的办法
  15. SpringBoot常用注解之@Retryable
  16. java 可以做前端么_java怎么做前端?Java web前端必备技术
  17. lsass.exe和smss.exe病毒专杀工具——即磁碟机病毒专杀工具(转载)
  18. Python list列表---学习总结
  19. 4个免费又好用的wordpress企业主题
  20. 2008年七月七日,按照要求我提前进入中心,今天就是我博士的第一天

热门文章

  1. 那些德艺双馨的网站列表-updating
  2. 如何发布打印机文件夹及ICA 客户端打印机配置工具
  3. Windows Phone 8初学者开发—第12部分:改进视图模型和示例数据
  4. Acey.ExcelX组件如何保证稳定性?
  5. 错误:mysql foreign key errno 150
  6. linux入门教程(二)
  7. 最终成为了热门的语言——python
  8. 关闭Eclipse回车自动添加大括号
  9. svnserve.conf: Option expected的问题解决方法
  10. 解决IE只能用管理员身份运行才能正常