天天看点

原子操作CAS并发编程–原子操作CAS

并发编程–原子操作CAS

1.预备概念

CAS:(compared and sweep)比较后进行交换,是一种乐观锁的设计思想。

synchronized:是以一种基于悲观锁的实现。

原子操作:不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换,在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段,需要硬件支持。

2.CAS原理

一.实现原理:

流程

比较后进行交换,当更新值的时候,带上旧值,如果旧值和当前变量的值相等,那就认为该数据没有被更其他线程操作过,再把新值赋值给该变量。

  1. 第一步当前线程通过旧值经过计算得到新值。
  2. compare内存中变量值和旧值,如果相等进入下一步。
  3. 旧值swap为新值。

带来的问题:

  1. ABA问题:利用CAS确保原子性,会带来ABA问题,所以常见的CAS一般带有版本号来确定是否有ABA问题。***cas(内存地址,旧值,新值)***。
  2. 开销问题:当旧值和内存中的值不相等,重新进入一次计算,可能导致死循环。
  3. 效率问题:一次CAS只能操作一个变量,当有多个变量需要组合更改。

利用CAS实现的原子操作类

更新基本类型的:AtomicBoolean AtomicInteger AtomicLong

更新数组的:AtomicIntegerArray AtomicLongArray

更新引用类型的:AtomicReference AtomicMarkableReference.

AtomicIntegerArray 测试:

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerTest {

    public static void main(String[] args) {
        int [] integers = new int[]{1,2};

        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(integers);

        atomicIntegerArray.set(0,3);
        System.out.println(atomicIntegerArray.get(0));
        System.out.println(integers[0]);
    }
}
           

运行结果:

3
1
~~~java
AtomicMarkedReference:通过boolean是否修改的方式保持原子性。
AtomicStampReference:通过版本戳的形式去保持原子更新,更新的版本可控。

测试代码:AtomicMarkedReferenceTest
package cn.enjoyedu.ch3;

import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampReferenceTest {

    public static void main(String[] args) throws InterruptedException {
        AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
        //声明一个引用
//        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);
        AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicMarkableReference<AtomicReferenceTest.UserInfo>(userInfo,false);

        //声明两个线程去修改
        Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
        thread.start();
        thread.join();
        Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
        thread2.start();

    }
    static class ThreadModify1 extends Thread{
        AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify1(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //获取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            boolean stamp = atomicStampedReference.isMarked();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
            System.out.println(currentThread().getName()+b);
        }
    }

    static class ThreadModify2 extends Thread{
        AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify2(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //获取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            boolean stamp = atomicStampedReference.isMarked();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
            System.out.println(currentThread().getName()+b);
        }
    }


}
           

运行结果:

Thread-1true
Thread-3false
           

测试代码:AtomicStampReferenceTest

import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampReferenceTest {

    public static void main(String[] args) throws InterruptedException {
        AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
        //声明一个引用
        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);

        //声明两个线程去修改
        Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
        thread.start();
        thread.join();
        Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
        thread2.start();

    }
    static class ThreadModify1 extends Thread{
        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify1(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //获取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            int stamp = atomicStampedReference.getStamp();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, stamp + 2);


            System.out.println(currentThread().getName()+b);
        }
    }

    static class ThreadModify2 extends Thread{
        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify2(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //获取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            int stamp = 0;
            //atomicStampedReference.getStamp();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b= atomicStampedReference.compareAndSet(userInfo,deer,stamp,stamp+2);
            System.out.println(currentThread().getName()+b);
        }
    }


}

           

运行结果:

Thread-1true
Thread-3false
           

继续阅读