并发编程时,对于共享资源的使用需要确保绝对的安全性。除了利用锁机制之外,还有一种无锁的概念。所谓无锁,就是假定在并发情况下,对于共享资源的访问没有冲突,线程可以一直不停的运行,无需阻塞,如果产生冲突,则使用CAS算法确保安全性。Java在很多并发代码中都使用了这种算法。

  CAS算法的核心参数如下:

compareAndSet(V,E,A)

  V代码需要进行更新的变量;E代表预期值;A代表所要更新的值。

  CAS的核心思想就是:当要对一个变量进行更新时,先取出该变量此时在内存中的实际值,与预期值进行比较。如果相等,则代表没有其他线程对其进行过修改,直接更新。如果不同,表示有其他线程修改过,此时有两种策略。一种是让CAS自旋,直到更新成功;另外表示当前线程更新失败,继续后续逻辑。大概示意图如下:

  对于CAS自旋,有可能会出现长时间更新失败,浪费CPU性能的情况。JDK1.6以后,加入了适应性自旋的概念。即如果某个锁自旋时很少获得成功,那么会减少自旋次数。自旋次数的默认值是10次,可以使用参数-XX:PreBlockSpin来更改。

  再说一下为什么CAS在更新变量值的时候不会受到其他线程的影响呢?会不会我在判断更新值与预期值相等,进行更新的过程中,变量被其他线程更新了呢?其实不会,因为CAS具有排它性,一次CAS是一个原子操作,是CPU源语级别。确保隔离性。

  Java对于CAS是使用Unsafe类进行支持的。顾名思义,不安全,可以让程序员像C语言那样直接操纵内存指针。java.util.concurrent.atomic包下的类,都是使用CAS实现的。

ABA缺陷

  不知道大家通过上面对CAS的介绍说明,看到了CAS算法的缺陷没有!

  CAS本身会有ABA问题。举个例子,变量m = 10,我要把m更新为30。在我判断之前,有其他线程先把m更新到50,在从50更新到10。那么我进行 10 == 10的判断时,这时候我怎么确定m的值有没有被改过呢?这就是ABA问题了。

  要解决这个问题,我们就需要在进行 10 == 10判断的时候,还需要有其他参照。Java中有一个类AtomicStampedReference,这个类除了维护变量值之外,还会维护一个时间戳。用于确定数值版本。

private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
} private volatile Pair<V> pair;

  用volatile关键字修饰的内部类。

  

  看一下核心的compareAndSet()方法:

public boolean compareAndSet(V   expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}

  可以看到除了比较数值之外,还会比较时间戳。

CAS无锁策略的更多相关文章

  1. (转载)java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  2. CAS无锁算法与ConcurrentLinkedQueue

    CAS:Compare and Swap 比较并交换 java.util.concurrent包完全建立在CAS之上的,没有CAS就没有并发包.并发包借助了CAS无锁算法实现了区别于synchroni ...

  3. java并发:AtomicInteger 以及CAS无锁算法【转载】

    1 AtomicInteger解析 众所周知,在多线程并发的情况下,对于成员变量,可能是线程不安全的: 一个很简单的例子,假设我存在两个线程,让一个整数自增1000次,那么最终的值应该是1000:但是 ...

  4. CAS无锁机制原理

    原子类 java.util.concurrent.atomic包:原子类的小工具包,支持在单个变量上解除锁的线程安全编程 原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读 ...

  5. CAS无锁实现原理以及ABA问题

    CAS(比较与交换,Compare and swap) 是一种有名的无锁算法.无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(N ...

  6. CAS无锁技术

    前言:关于同步,很多人都知道synchronized,Reentrantlock等加锁技术,这种方式也很好理解,是在线程访问的临界区资源上建立一个阻塞机制,需要线程等待 其它线程释放了锁,它才能运行. ...

  7. 探索CAS无锁技术

    前言:关于同步,很多人都知道synchronized,Reentrantlock等加锁技术,这种方式也很好理解,是在线程访问的临界区资源上建立一个阻塞机制,需要线程等待 其它线程释放了锁,它才能运行. ...

  8. CAS无锁操作

    https://coolshell.cn/articles/8239.html 主要讲的是<Implementing Lock-Free Queues>的论点,具体直接看论文最好.这里总结 ...

  9. CAS无锁模式

    一.java内存模型:JMM 在内存模型当中定义一个主内存,所有声明的实例变量都存在于主内存当中,主内存的数据会共享给所有线程,每一个线程有一个块工作内存,工作内存当中主内存数据的副本当更新数据时,会 ...

随机推荐

  1. Intellij IDEA中如何给main方法赋args

    Intellij IDEA中如何给main方法赋args 程序: package com.otherExample; /** * Created by 谭雪娇 on 2017/3/29. */publ ...

  2. 如何在微信小程序中使用iconfont

    开篇废话 开发过小程序的童鞋肯定都会遇到这样的问题,当我们在小程序中使用iconfont官方推荐的方法插入字体时,我们总会得到一个打印机(滑稽).那么如何在小程序中正确的使用iconfont呢? 一. ...

  3. vue2.0 之 douban (六)axios的简单使用

    由于项目中用到了豆瓣api,涉及到跨域访问,就需要在config的index.js添加代理,例如 proxyTable: { // 设置代理,解决跨域问题 '/api': { target: 'htt ...

  4. 解决Docker容器 iptables问题---docker: Error response from daemon: driver failed programming external connectivity on endpoint quizzical_thompson

    一.问题现象 最近在研究Docker容器日志管理时,启动容器出现iptables相关报错,具体问题如下 运行容器 [root@node-11 ~]# docker run -d -p 24224:24 ...

  5. Ntdll.h

    转自:https://www.cnblogs.com/gwsbhqt/p/5092390.html 为了能使用上Ntdll.lib库函数,从几份不完整的Ntdll.h中拼凑整理出了比较完整美观的Ntd ...

  6. [WCF REST] WebServiceHost 不依赖配置文件启动简单服务

    最近用WPF启动 WCF REST 服务,发现app.config 配置好烦,简单一个exe 可以到处搬动,还非得带一个累赘配置,不小心丢了程序就跑不起来. 最后决定,砍去WCF配置项,用WebSer ...

  7. .NETFramework:System.Net.WebClient.cs

    ylbtech-.NETFramework:System.Net.WebClient.cs 提供用于将数据发送到和接收来自通过 URI 确认的资源数据的常用方法 1.返回顶部 1. #region 程 ...

  8. leetcode 238. 除自身以外数组的乘积 (python)

    给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积. 示例: 输入: [1 ...

  9. Netty精进01

    为什么要学习Netty? 目前基于Netty实现的一些优秀的开源框架:Dubbo.RocketMQ.Spark.Spring5.Flink.ElasticSearch.gRPC……这些还说明不了为什么 ...

  10. SHELL脚本里执行的东西需要多次回车确认,怎么实现自动回车确认?

    写了个自动配置的shell脚本,其中有几行是 …… ./build-key-server ./build-key-client …… 在执行build-key-server和build-key-cli ...