这是我参考的一篇文章《基于CAS的乐观锁实现》,讲述的是一种需要CPU支持的执行技术CAS(Compare and Swap)。

首先理解什么是原子性操作,意思是不能再拆分的操作,例如改写一个值,读取一个值都属于原子性操作。

那么CAS是两个操作,先比较旧值,比较通过后再进行改写,这种连合操作合并成一个指令交给CPU,由CPU操作来确保这是一个原子性操作。

多线程同时改写同一个值时,每个线程携带自己的旧值和新值交给CPU改写,CPU的运行是按逐条指令运行,如果发现旧值不符合,线程就会收到改写失败回应。

public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}

因此AtomicInteger#incrementAndGet()方法里,会循环尝试使用compareAndSet(...)方法,直到成功为止。

相关的原子类所在包:java.util.concurrent.atomic

  • Atomic + Boolean/Integer/Long/Reference
    操作一个对应的类型对象
  • Atomic + Integer/Long/Reference + Array
    操作一个对应类型的数组

  • Atomic + Integer/Long/Reference + FieldUpdater
    操作一个对应类型的Field对象,类似反射方式改写对象字段

这里《AtomicStampedReference解决ABA问题》,讲述了原子类会出现ABA时带来的隐患,文中举了一个例子,一个单向的链表实现了堆栈操作,使用一个原子变量作为链头指针,现在链头是A,A的next是B。有两个线程分别是T1和T2,他们并发的操作如下:

  • T1:AB => B
  • T2:AB => B => 空 => D => CD => ACD

由于线程T1只认链头是不是A,如果是A,就会将链头指向B,因此可能会出现直接把ACD变成B,这就是ABA并发的隐患。

  • AtomicMarkableReference
    操作一个对象类型和boolean类型的二元组
  • AtomicStampedReference
    操作一个对象类型和int类型的二元组

虽然例子中链头指针是一个原子变量,会出现ABA的情况,但如果再增加一个原子变量,这个原子变量确保不会出现ABA的情况,两个原子变量作为二元组进行原子性操作,即使用AtomicStampedReference就可以有效解决这个ABA的隐患了。

以下是Java8增加的原子类:

  • Striped64
  • Long/Double + Adder
  • Long/Double + Accumulator

这里有两篇文章,内容是分析它们的源码:《从LongAdder 看更高效的无锁实现》《LongAdder和LongAccumulator》

源码有些复杂,我也没看完,Striped64是这项新原子类的基类,它提供的原理是,把一个原子数拆分成多个原子数,最后把这多个原子数合成一个数。换句话说,原本在一个数上做递增或者递减操作的,现在变成在多个数里,选择其中一个做做递增或递减操作,那么加起来的结果与原本方式的结果是等价的。虽然是等价,但它结算结果的过程,是需要把多个数加起来,这个过程已经不是线程安全了,所以它的应用场合相比原本方式会宽一点,原本方式所取出来的值可以作为唯一ID,但现在方式只能用于统计。试想,如果有1000个线程同时在统计同一个数据,那么原本方式的原子类,就会失败率上升,效率也会随之下降。但如果把1000个线程,分成10份,每100个线程统计同一个数据,那么产生10个数据,最后统计的结果就是这10个数据叠加一起的结果,失败率当然因份数的增加而减少,效率也自然有保障。

应用场合:高并发,统计数据。

多线程同步工具——CAS原子变量的更多相关文章

  1. 多线程同步工具——volatile变量

    关于volatile,找了一堆资料看,看完后想找一个方法去做测试,测了很久,感觉跟没有一样. 这本书<深入理解Java内存模型>,对volatile描述中有这样一个比喻的说法,如下代码所示 ...

  2. Java多线程并发编程之原子变量与非阻塞同步机制

    1.非阻塞算法 非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 -- 例如比较和交换.非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞 ...

  3. Java多线程同步工具类之CountDownLatch

    在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...

  4. Java多线程同步工具类之Semaphore

    Semaphore信号量通常做为控制线程并发个数的工具来使用,它可以用来限制同时并发访问资源的线程个数. 一.Semaphore使用 下面我们通过一个简单的例子来看下Semaphore的具体使用,我们 ...

  5. C++11 多线程同步 互斥锁 条件变量

    在多线程程序中,线程同步(多个线程访问一个资源保证顺序)是一个非常重要的问题,Linux下常见的线程同步的方法有下面几种: 互斥锁 条件变量 信号量 这篇博客只介绍互斥量和条件变量的使用. 互斥锁和条 ...

  6. 多线程同步工具——Lock

    本文原创,转载请注明出处. 参考文章: <"JUC锁"03之 公平锁(一)> <"JUC锁"03之 公平锁(二)> 锁分独占锁与共享锁, ...

  7. Java多线程同步工具类之CyclicBarrier

    一.CyclicBarrier使用 CyclicBarrier从字面上可以直接理解为线程运行的屏障,它可以让一组线程执行到一个共同的屏障点时被阻塞,直到最后一个线程执行到指定位置,你设置的执行线程就会 ...

  8. 多线程同步工具——LockSupport

    用例1:子线程等待主线程发放许可! public static void main(String[] args) { Thread thread = new Thread(){ public void ...

  9. Java多线程-----原子变量和CAS算法

       原子变量      原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题      Java给我们提供了以下几种原子类型: AtomicInteger和Ato ...

随机推荐

  1. 我为什么要写LeetCode的博客?

    # 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...

  2. IE8/9 本地预览上传图片

    本地预览的意思是,在选择图片之后先不上传到服务器,而是由一个<img>标签来预览本地的图片,非 IE8/9 浏览器可以从<input type="file"/&g ...

  3. 在centos7上安装ClamAV杀毒,并杀毒(centos随机英文10字母)成功

    前言 上传文件的时候发现总是失败,查看top发现有个进程一直cpu占用80%以上,而且名称还是随机数.kill之后,一会儿又重新生成了.突然发现居然没有在服务端杀毒的经历.在此处补齐. 安装clama ...

  4. Boost信号/槽signals2

    信号槽是Qt框架中一个重要的部分,主要用来解耦一组互相协作的类,使用起来非常方便.项目中有同事引入了第三方的信号槽机制,其实Boost本身就有信号/槽,而且Boost的模块相对来说更稳定. signa ...

  5. BPM配置故事之案例7-公式计算

    行政主管发来邮件.要求物资明细表增加"单价""总价"."单价"由其审批时填写,"总价"根据"单价"与 ...

  6. win7下利用ftp实现华为路由器的上传和下载

    win7下利用ftp实现华为路由器的上传和下载 1.  Win7下ftp的安装和配置 (1)开始->控制面板->程序->程序和功能->打开或关闭Windows功能 (2)在Wi ...

  7. 微信开发笔记(accesstoken)

    access_token分两种 一种是公众号权限获取用,调用cgi-bin接口 ,此种token一个公众号同时只有一个,用这一个就够了. 服务器最好缓存. 用这个token前提是用户关注了此公众号. ...

  8. Android之SharedPreferences数据存储

    一.SharedPreferences保存数据介绍 如果有想要保存的相对较小键值集合,应使用SharedPreferences API.SharedPreferences对象指向包含键值对的文件并提供 ...

  9. 一步步学习javascript基础篇(0):开篇索引

    索引: 一步步学习javascript基础篇(1):基本概念 一步步学习javascript基础篇(2):作用域和作用域链 一步步学习javascript基础篇(3):Object.Function等 ...

  10. JAAS 是个什么梗

    参考资料 该文中的内容来源于 Oracle 的官方文档.Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以从这个总入口 Java SE 8 Documentati ...