Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference

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等.

Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference

其中AtomicInter继承 Number 实现 Serializable接口

Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference

应用

方法:
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操作。

Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference

方法:

//   用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()首先检查当前引用和当前标志与预期引用和预期标志是否相等,如果都相等,则以原子方式将引用值和标志的值设置为给定的更新值。

上一篇:ent orm笔记1---快速尝鲜


下一篇:CAD闪烁实体