多线程开发中确保这三大特性。首先,最简单的方式就是使用 synchronized 关键字或者其它加锁。这种方式最大的好处是–简单!不需要动脑子,在需要的地方加锁就好了。同步方式在并发时包治百病,但治病的手段却是让多线程程序转为串行执行,这相当于自毁武功,浪费资源。如果滥用同步,那么程序就是去了多线程的意义。因此,只有在必要的时候才使用同步。比如对共享资源的访问。而且尽量控制同步代码块的范围,不需要使用同步的代码,尽量不要放入同步代码块。所以java还提供了轻量级的实现,来解决特定的问题,虽然没有普遍性,只是针对某些特定的问题提供的实现。但是这样已经能够解决问题,还能提高代码效率。

原子性的轻量级实现-Atomic

Atomic 相关类在 java.util.concurrent.atomic 包中。针对不同的原生类型及引用类型,有 AtomicInteger、AtomicLong、AtomicBoolean、AtomicReference 等。另外还有数组对应类型 AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。由于 Atomic 提供的功能类似,就不一个个过了。我们以 AtomicInteger 为例,看看 Atomic 类型变量所能提供的功能。

我们首先举个例子来验证AtomicInteger 的原子性
首先我们看没有加这个字段修饰的代码以及运行结果


public class T01_AtomicInterger {Integer count = new Integer(0);void m() {for (int i = 0; i < 10000; i++) {count++; //count++}}public static void main(String[] args) {T01_AtomicInterger t = new T01_AtomicInterger();List<Thread> threads = new ArrayList<>();for (int i = 0; i < 10; i++) {threads.add(new Thread(t::m, "thread-" + i));}threads.forEach((o) -> o.start());threads.forEach((o) -> {try {o.join();} catch (InterruptedException e) {e.printStackTrace();}});System.out.println(t.count);}}

这段代码时启动了十个线程,每个线程执行 10000次对count的加一操作,最后的结果理论上是100000。但是结果却不是

运算逻辑是对变量 count 的累加。假如 count 为 int 类型,多个线程并发时,可能各自读取到了同样的值,也可能 A 线程读到 2,但由于某种原因更新晚了,count 已经被其它线程更新为了 4,但是线程 A 还是继续执行了 count+1 的操作,count 反而被更新为更小的值 3。现在的多线程程序是不安全的。故会造成上述的结果,其实我们有最简单的解决办法加锁,就是让加一操作由异步变成同步就行,我们看下边的代码:

    synchronized  void m() {for (int i = 0; i < 10000; i++) {count++; //count++}}

最后的运算结果如下:


 确实得到 了正确的答案,但是我上次说过了,加锁是需要开销的。所以java提供了更加轻量级的实现--AtomicInteger

我么需要将count用 AtomicInteger修饰,加一的操作不需要用synchronized  修饰了,直接使用Atomic的incrementAndGet方法,也就是加一操作,这样就实现了原子性操作。

    AtomicInteger count = new AtomicInteger(0);/*synchronized */ void m() {for (int i = 0; i < 10000; i++) {count.incrementAndGet(); //count++}}

运算结果如下;

也是可以实现加一操作的,而且保证了安全性,并且没有加锁,提高了代码的运行效率。其实count=count+1 这行语句其实隐含了两步操作,第一步取得 count 的值,第二步为 count 加 1 。而在这两步操作中间,count 的值可能已经改变了。而 AtomicInteger 提供的 incrementAndGet () 方法,则把这两步操作作为一个原子性操作来完成,则不会出现线程安全问题。

而Atomic如何实现了原子性呢?其实使用了CAS算法。

CAS 算法

CAS 是 Compare and swap 的缩写,翻译过来就是比较替换。其实 CAS 是乐观锁的一种实现。而 Synchronized 则是悲观锁。这里的乐观和悲观指的是当前线程对是否有并发的判断。

悲观锁–认为每一次自己的操作大概率会有其它线程在并发,所以自己在操作前都要对资源进行锁定,这种锁定是排他的。悲观锁的缺点是不但把多线程并行转化为了串行,而且加锁和释放锁都会有额外的开支。

乐观锁–认为每一次操作时大概率不会有其它线程并发,所以操作时并不加锁,而是在对数据操作时比较数据的版本,和自己更新前取得的版本一致才进行更新。乐观锁省掉了加锁、释放锁的资源消耗,而且在并发量并不是很大的时候,很少会发生版本不一致的情况,此时乐观锁效率会更高。

Atomic 变量在做原子性操作时,会从内存中取得要被更新的变量值,并且和你期望的值进行比较,期望的值则是你要更新操作的值。如果两个值相等,那么说明没有其它线程对其更新,本线程可以继续执行。如果不等,说明有线程已经先于此线程进行了更新操作。那么则继续取得该变量的最新值,重复之前的逻辑,直至操作成功。这保证了每个线程对 Atomic 变量操作是线程安全的。

CAS缺点 : ABA 问题

假如本线程更新前取得期望值为 A,和更新操作之间的这段时间内,其它线程可能把 value 改为了 B 又改回了 A。 而本线程更新时发现 value 和期望值一样还是 A,认为其没有变化,则执行了更新操作。但其实此时的 A 已经不是彼时的 A 了。

【并发编程】Atomic与CAS相关推荐

  1. Java并发编程-无锁CAS与Unsafe类及其并发包Atomic

    [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772470 出自[zejian ...

  2. 并发编程-Atomic的compareAndSet

    接上一篇博客并发编程-多线程共享变量不安全,分析Atomic原子类是怎么保证线程安全的. 并发三个基本概念: 1.原子性:操作是线程私有的,不能拆分成多个步骤,被其他线程影响:(官方版:操作不可中断, ...

  3. java cas机制_java并发编程中的CAS机制,你理解嘛?

    学习Java并发编程,CAS机制都是一个不得不掌握的知识点.这篇文章主要是从出现的原因再到原理进行一个解析.希望对你有所帮助. 一.为什么需要CAS机制? 为什么需要CAS机制呢?我们先从一个错误现象 ...

  4. Java并发编程—Atomic原子类

    目录 Atomic 1. AtomicInteger a. 多线程并发访问问题 b. 用 AtomicInteger 类解决 2. AtomicIntegerArray a. 多线程并发访问问题 b. ...

  5. Java并发编程,无锁CAS与Unsafe类及其并发包Atomic

    为什么80%的码农都做不了架构师?>>>    我们曾经详谈过有锁并发的典型代表synchronized关键字,通过该关键字可以控制并发执行过程中有且只有一个线程可以访问共享资源,其 ...

  6. atomic原子类实现机制_并发编程:并发操作原子类Atomic以及CAS的ABA问题

    本文基于JDK1.8 Atomic原子类 原子类是具有原子操作特征的类. 原子类存在于java.util.concurrent.atmic包下. 根据操作的数据类型,原子类可以分为以下几类. 基本类型 ...

  7. 面试准备每日系列:计算机底层之并发编程(一)原子性、atomic、CAS、ABA、可见性、有序性、指令重排、volatile、内存屏障、缓存一致性、四核八线程

    文章目录 1. 什么是进程?什么是线程? 2. 线程切换 3. 四核八线程是什么意思 3.1 单核CPU设定多线程是否有意义 4. 并发编程的原子性 4.1 如何解决原子性问题 & atomi ...

  8. cas无法使用_并发编程中cas的这三大问题你知道吗?

    在java中cas真的无处不在,它的全名是compare and swap,即比较和交换.它不只是一种技术更是一种思想,让我们在并发编程中保证数据原子性,除了用锁之外还多了一种选择. 一.cas的思想 ...

  9. 并发编程-04线程安全性之原子性Atomic包的4种类型详解

    文章目录 线程安全性文章索引 脑图 概述 原子更新基本类型 Demo AtomicBoolean 场景举例 原子更新数组 Demo 原子更新引用类型 Demo 原子更新字段类型 使用注意事项: Dem ...

  10. 并发编程-03线程安全性之原子性(Atomic包)及原理分析

    文章目录 线程安全性文章索引 脑图 线程安全性的定义 线程安全性的体现 原子性 使用AtomicInteger改造线程不安全的变量 incrementAndGet源码分析-UnSafe类 compar ...

最新文章

  1. 顶尖学者加盟!两所C9高校,获强援!
  2. 数值分析之数值稳定性篇
  3. 四层和七层负载均衡的区别介绍--转
  4. 两个线程如何交替执行,一个输出偶数一个输出奇数?
  5. 产品经理如何走出被运营牵着鼻子走的怪圈
  6. orcale的rank(排名函数)实例
  7. 作者:姚登举(1980-),男,哈尔滨理工大学副教授。
  8. mybatis与Spring整合配置文件
  9. Java获取http和https协议返回的json数据
  10. 2016/7/7 设置wamp2.5 mysql密码 重点是mysql版本
  11. 新概念单片机c语言 pdf,新概念51单片机C语言教程实例代码(1).pdf
  12. PCB绘图的基本要求和布线原则
  13. 如何做职业规划并进行求职准备(持续更新)
  14. A-GPS学习笔记(二) 之SUPL
  15. Google浏览器书签栏优化
  16. 国有银行信息科技岗笔试内容
  17. GVRP和VTP的比较与区别
  18. 计算机视觉关于进化计算表达方式0.0.6
  19. 【Linux服务器管理】1、用户与权限
  20. 外贸网站到底选什么购物车网店系统最好

热门文章

  1. linux alpine 提示'/bin/sh: rc-service: not found'解决方案
  2. linux gcc 宏定义 __GNUC__ __GNUC_MINOR__ 版本区分
  3. 堆溢出DWORD SHOOT原理
  4. Win7 64位的SSDTHOOK(2)---64位SSDT hook的实现
  5. Shell中read的常用方式
  6. Design Pattern - Adapter(C#)
  7. Windows - Windows批处理
  8. Linux内核网络数据包发送(二)——UDP协议层分析
  9. 成都计算机大专学校公办,成都设有计算机应用技术的公办大专学校
  10. android 使用perl语言,在Android上用python(Perl、Lua、BeanShell等)编程