Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference

什么是CAS?

什么是CAS? 即比较并替换,实现并发算法时常用到的一种技术。CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。我们都知道,CAS是一条CPU的原子指令(cmpxchg指令),不会造成所谓的数据不一致问题,Unsafe提供的CAS方法(如compareAndSwapXXX)底层实现即为CPU指令cmpxchg。

*  CAS
* @param o 包含要修改field的对象
* @param offset 对象中某field的偏移量
* @param expected 期望值
* @param update 更新值
* @return true | false
*/
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object update); public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update); public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);

AtomicInteger:

AtomicInteger代表着基本类型的原子类:其中有AtomicInteger、AtomicBoolean、AtomicLong等.

其中AtomicInter继承 Number 实现 Serializable接口

应用

方法:

1)public AtomicInteger();//初始化该类。初始值为0

2)public AtomicInteger( int initialValue) //给定初始值的初始化

在程序中需要原子的增加或减少计数器时,使用此类 AtomicInteger

public class Counter{
        private AtomicInteger ia =  new AtomicInteger();
        public void increase(){
            ia.getAndIncrement();
        }
        public int get(){
            return ia.get();
        }
    }
    public class Worker extends Thread{
        Counter counter;
        public Worker( Counter counter){
            this.counter = counter;
        }
        public void run (){
            for(int i=0;i<100;i++){
                counter.increase();
            }
        }
    }
    public class Index{
        public static void main(String[] args){
            Counter counter = new Counter(0;
            Thread t1 = new Worker(counter);
            Thread t2 = new Worker(counter);
            t1.start();
            t2.start();
            try{
                t1.jion();
                t2.jion();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("counter.get() = " + counter.get());
        }
    }

AtomicReference

上面讲到AtomicInteger对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。

Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。

方法:

//   用V来指明应用的类型
public AtomicReference() // 用初始值null创建类AmoticReference的实例。
public AtomicReference( V initialValue) // 用初始initialValue 创建类AtomicReference的实例,
 //举例
public class Counter(){
        private AtomicReference<Integer> af = new AtomicReference<Integer>(0);
        public void increase(){
            Integer temp = af.get();
            af.comparseAndSet( temp,temp+1);
        }
        public Integet get(){
            return af.get();
        }
    }
    public class Worker extends Thread{
        Counter counter;
        public Worker( Counter counter){
            this.counter = counter;
        }
        public void run (){
            for(int i=0;i<100;i++){
                counter.increase();
            }
        }
    }
    public class Index{
        public static void main(String[] args){
            Counter counter = new Counter(0;
            Thread t1 = new Worker(counter);
            Thread t2 = new Worker(counter);
            t1.start();
            t2.start();
            try{
                t1.jion();
                t2.jion();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("counter.get() = " + counter.get());
        }
    }

AtomicStampedReference

是什么?首先需要了解一下ABA问题

ABA问题是指在CAS操作中带来的潜在问题

CAS意思是 compare and swap 或者 compare and set , 对于一个要更新的变量A,我们提供一个它的旧值a 和新值 b ,如果变量A的值等于旧值 那么更新成功, 否则失败。

举例:

比如两个线程

  • 线程1 查询A的值为a,与旧值a比较,
  • 线程2 查询A的值为a,与旧值a比较,相等,更新为b值
  • 线程2 查询A的值为b,与旧值b比较,相等,更新为a值
  • 线程1 相等,更新B的值为c

可以看到这样的情况下,线程1 可以正常 进行CAS操作,将值从a变为c 但是在这之间,实际A值已经发了a->b b->a的转换

仔细思考,这样可能带来的问题是,如果需要关注A值变化过程,是会漏掉一段时间窗口的监控

另外:cas本身不是锁,只是cas很容易用来封装成锁,乐观锁只是一种思想,并不是真的有一种锁是乐观的。有些场景是不封装成锁直接使用cas,例如对AtomicInteger的increase,这就是乐观锁思想的实践,所以AtomicInteger.increase才能被称为无锁实现。

问题解决

JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题,具体操作封装在compareAndSet()中。compareAndSet()首先检查当前引用和当前标志与预期引用和预期标志是否相等,如果都相等,则以原子方式将引用值和标志的值设置为给定的更新值。

Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference的更多相关文章

  1. 并发和多线程(二)--线程安全、synchronized、CAS简介

    线程安全性: 当多个线程访问一个类的时候,这个类始终表示出正确的行为,那么这个类是线程安全的. 无状态的对象一定是线程安全的,例如大部分service.dao.Servlet都是无状态的. 线程安全体 ...

  2. CAS导致的ABA问题及解决:时间戳原子引用AtomicReference、AtomicStampedReference

    1.CAS导致ABA问题: CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并交换,那么在这个时间差中会导致数据的变化. 比如:线程1从内存位置V中取出A,这时线程2也从V中取出A ...

  3. AtomicReference、AtomicStampedReference 和 AtomicMarkableReference

    这三个都是自 JDK1.5 开始加入到 java.util.concurrent.atomic 下面的.他们都可以在 lock-free 的情况下以原子的方式更新对象引用. 一.AtomicRefer ...

  4. 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法

    转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...

  5. Java多线程之原子性 volatile、atomicInteger测试

    原文链接:http://www.cnblogs.com/zhengbin/p/5653051.html 一.补充概念 1.什么是线程安全性? <Java Concurrency in Pract ...

  6. java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)

    一.介绍 首先, java 的锁分为两类: 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 jvm 层面实现,使用的时候看不见: 第二类是在 jdk5 后增加的 Lock ...

  7. JAVA CAS原理、unsafe、AQS

    concurrent包的实现 由于java的CAS同时具有 volatile 读和volatile写的内存语义,因此Java线程之间的通信现在有了下面四种方式: A线程写volatile变量,随后B线 ...

  8. 深入介绍Java中的锁[原理、锁优化、CAS、AQS]

    1.为什么要用锁? 锁-是为了解决并发操作引起的脏读.数据不一致的问题. 2.锁实现的基本原理 2.1.volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新, ...

  9. Java中的锁[原理、锁优化、CAS、AQS]

    1.为什么要用锁? 锁-是为了解决并发操作引起的脏读.数据不一致的问题. 2.锁实现的基本原理 2.1.volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新, ...

  10. Java中的锁原理、锁优化、CAS、AQS详解!

    阅读本文大概需要 2.8 分钟. 来源:jianshu.com/p/e674ee68fd3f 一.为什么要用锁? 锁-是为了解决并发操作引起的脏读.数据不一致的问题. 二.锁实现的基本原理 2.1.v ...

随机推荐

  1. VS2013连接SQLSERVER数据库时显示无法添加数据连接

    VS2013连接sqlserver2008时出现如下错误: VS2013添加Microsoft SQL Server数据源时,会遇到无法添加数据连接. Could not load file or a ...

  2. C#/VB.NET:如何将PDF转为PDF/A

    PDF/A是一种ISO标准的PDF文件格式版本,是为长期保存文件而设计的.它提供了一种工具,使电子文件在长时间之后依然以一种保留其外观的方式重现,而不管该文件是用什么工具和系统创建.储存或制作的.这种 ...

  3. 提供一款局域网聊天小工具,对接了chatGPT3.5

    账号.密码随便填,只要自己能记住就可以,网络地址如效果图(本机IP地址+8080端口),效果图如下 服务地址用本机IP,端口可以随便用一个,如8888,填完记得点击按钮开启: 通讯地址如果你有其他人的 ...

  4. 有关Spring的ioc理解之代理模式

    AOP代理模式可以实现事务控制和业务逻辑代码横切. 使用代理模式,动态代理实现横切. 什么是代理? 接口就是指定要做的事情,要实现的逻辑. 代理类似于房源租房 public interface ZuF ...

  5. Java设计模式 —— 工厂模式

    3 简单工厂模式 3.1 创建型模式 Creational Pattern 关注对象的创建过程,对类的实例化过程进行了抽象,将软件模块中对象的创建和对象的使用分离,对用户隐藏了类的实例的创建细节.创建 ...

  6. Go语言:两种常见的并发模型

    Go语言:两种常见的并发模型 在并发编程中,须要精确地控制对共享资源的访问,Go语言将共享的值通过通道传递 并发版"Hello World" 使用goroutine来打印" ...

  7. C#模拟C++模板特化对类型的值的支持

    概述 C++的模板相比于C#,有很多地方都更加的灵活(虽然代价是降低了编译速度),比如C++支持变长参数模板.支持枚举.int等类型的值作为模板参数. C++支持枚举.int等类型的值作为模板参数,为 ...

  8. 基于Canal实现MySQL 8.0 数据库数据同步

    前言 服务器说明 主机名称 操作系统 说明 192.168.11.82 Ubuntu 22.04 主库所在服务器 192.168.11.28 Oracle Linux Server 8.7 从库所在服 ...

  9. RK3568用户自定义开机画面功能

    RK方案中的开机画面处画逻辑 在RK的方案中,如RK1109,RK1126,RK3568这些嵌入式LINUX方案在开机画面的处理逻辑都是一致的. 用户的uboot,kernel开机画面都是同dts,k ...

  10. JavaWeb 中 Filter过滤器

    Filter过滤器 每博一文案 师傅说:人生无坦途,累是必须的背负,看多了,人情人暖,走遍了离合聚散,有时会 在心里对自己说,我想,我是真的累了,小时候有读不完的书,长大后有赚不尽的力. 白天在外要奋 ...