一 简介

保证Java中的原子操做方式有两种方式
  1 加锁(可以理解悲观锁机制)
  2 CAS(可以理解为乐观锁机制)
  CAS全称是Compare and Swap 即比较并替换。在JDK中许多地方都可以看到它的身影,比如AQS同步组件,Atomic原子类操作等等都是以CAS实现的。其中java.util.concurrent 中的许多概念源自 Doug Lea 的 util.concurrent 库,而Doug lea大神在同步组件中大量使用使用CAS技术鬼斧神工地实现了Java多线程的并发操作。

二 CAS原理

在CAS中有三个参数:内存值V、旧的预期值A,要更新的值B。更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
来看一下Atomic包的源码中是如何使用的CAS,并分析它的原理
AtomicInteger的成员变量

     // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;

  

AtomicInteger的成员变量进行说明
1 Unsafe 
Java语言不像C,C++那样可以直接访问底层操作系统,但是JVM为我们提供了一个后门,这个后门就是unsafe。unsafe为我们提供了硬件级别的原子操作 。
2 valueOffset
至于valueOffset对象,是通过unsafe.objectFieldOffset方法得到,所代表的是AtomicInteger对象value成员变量在内存中的偏移量。我们可以简单地把valueOffset理解为value变量的内存地址。
3 value
被volatile所修饰被volatile的特点就不在说明了上一篇文章已经提到过了。
AtomicInteger的compareAndSet()

  /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//Unsafe.class
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

这个方法是修改值的方法,参数要求传两个参数期望值和要更新的值,如果更新成功的话返回true,反之亦然。在方法内部调用的是Unsafe的compareAndSwapInt,传而unsafe的compareAndSwapInt方法参数包括了这三个基本元素:valueOffset参数代表了V,expect参数代表了A,update参数代表了B。

正是unsafe的compareAndSwapInt方法保证了Compare和Swap操作之间的原子性操作。

三 CAS的问题

1.ABA问题
因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
2.循环时间长CPU开销大
自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销
3.只能保证一个共享变量的原子操做

并发系列(四)-----CAS的更多相关文章

  1. java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)

    1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...

  2. java高并发系列 - 第21天:java中的CAS操作,java并发的基石

    这是java高并发系列第21篇文章. 本文主要内容 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库乐观锁的一个常见示例 使用ja ...

  3. Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析

    学习Java并发编程不得不去了解一下java.util.concurrent这个包,这个包下面有许多我们经常用到的并发工具类,例如:ReentrantLock, CountDownLatch, Cyc ...

  4. Java 并发系列之二:java 并发机制的底层实现原理

    1. 处理器实现原子操作 2. volatile /** 补充: 主要作用:内存可见性,是变量在多个线程中可见,修饰变量,解决一写多读的问题. 轻量级的synchronized,不会造成阻塞.性能比s ...

  5. Java并发编程之CAS二源码追根溯源

    Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...

  6. Java高并发系列——检视阅读

    Java高并发系列--检视阅读 参考 java高并发系列 liaoxuefeng Java教程 CompletableFuture AQS原理没讲,需要找资料补充. JUC中常见的集合原来没讲,比如C ...

  7. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  8. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  9. 分布式系列四: HTTP及HTTPS协议

    分布式系列四: HTTP及HTTPS协议 非常全面的一篇HTTP的文章: 关于HTTP协议,一篇就够了 还有一个帮助理解HTTPS的文章: 也许,这样理解HTTPS更容易 本文的一些描述摘自这篇文章 ...

  10. java高并发系列-第1天:必须知道的几个概念

    java高并发系列-第1天:必须知道的几个概念 同步(Synchronous)和异步(Asynchronous) 同步和异步通常来形容一次方法调用,同步方法调用一旦开始,调用者必须等到方法调用返回后, ...

随机推荐

  1. "字符串"经过strip 之后还是字符串, 而"字符串"经过split 分开后,就变成了一个列表["x","xx","xxx"]

    "字符串"经过strip 之后还是字符串, 而"字符串"经过split 分开后,就变成了一个列表["x","xx",&q ...

  2. UI(二)之正式过程

    2018-12-04 09:48:25 1.SetWindowsHookEx ·钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统.每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获 ...

  3. Mina源码研究

    目录 1. NioSocketAcceptor初始化源码研究 1.1 类图 1.2 方法调用时序图 1.3 初始化NioSocketAcceptor 1.4 SimpleIoProcessorPool ...

  4. python第十六课——外部函数and内部函数

    1.外部函数&内部函数 内部函数: 定义在某个函数的内部,就是内部函数: [注意事项]: 1).内部函数可以随意使用它外部函数中的内容 2).外部函数不能使用内部函数中的内容 3).内部函数不 ...

  5. P3565 [POI2014]HOT-Hotels

    题目描述 There are nn towns in Byteotia, connected with only n-1n−1 roads. Each road directly links two ...

  6. RLE Iterator LT900

    Write an iterator that iterates through a run-length encoded sequence. The iterator is initialized b ...

  7. WebForm下的$.ajax中contentType: “application/json” 的用法

    不使用contentType: “application/json”则data可以是对象 $.ajax({ url: actionurl, type: "POST", datTyp ...

  8. Python之django自带的分页功能

    前端页面: <div class="col-sm-6"> <div class="dataTables_paginate paging_simple_n ...

  9. 域对象 request

    一)域对象: 1)request的生命周期: 从请求开始创建,到响应完成结束. 2)  作用:携带一次请求内的数据. 3)请求转发: 请求转发: 1)浏览器发送请求到服务器A,然后服务器A将请求转发到 ...

  10. HDU 2298(纯物理加解一元二次方程)

    Toxophily Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...