• 并发编程(十四):原子操作类



    学习资料

    《Java并发编程的艺术》第7章


    1.原子类简介

    java5提供了java.util.concurrent.atomic包,该包的原子操作提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,共12个类

    Atomic包里的类基本上都是使用Unsafe实现的包装类


    2.原子更新基本类型

    使用原子的方式更新基本类型三个类:AtomicBooleanAtomicIntegerAtomicLong

    用法几乎一样,AtomicInteger的常用方法如下:

    • AtomicInteger(n):构造方法,将对象内部值初始化为n
    • addAndGet(int n):将输入的值n与对象中的值相加并
    • compareAndSet(int expect,int update):如果对象中的值为expect,则将其原子地更新为update
    • getAndIncrement():以原子方式加1,返回原来的值
    • lazySet(int newValue):最终会设置为newValue,可能需要等一会才会设置
    • getAndSet(int newValue):以原子方式更新,并返回旧值

    使用方式:

    AtomicInteger atomicInteger=new AtomicInteger(1);
    System.out.println(atomicInteger.getAndIncrement());
    System.out.println(atomicInteger.get());
    

    原理:getAndIncrement()—>compareAndSet(int expect, int update)—>unsafe.compareAndSwapInt(this, valueOffset, expect, update)

    Unsafe提供了3种CAS方法,都是native方法:compareAndSwapObjectcompareAndSwapIntcompareAndSwapLong


    3.原子更新数组

    原子更新数组元素的3个类:AtomicIntegerArray(原子更新整型数组里的元素),AtomicLongArray(原子更新长整型),AtomicReferenceArray<E>(原子更新引用)

    AtomicIntegerArray常用方法:

    • addAndGet(int i,int n)int[i]=int[i]+n,原子的方式
    • compareAndSet(int i,int expect,int update)int[i]CAS

    使用方式:

    AtomicIntegerArray ai = new AtomicIntegerArray(new int[] { 1, 2 });
    ai.getAndSet(0,3);
    ai.get(0)
    

    不会修改传入的参数数组,内部会先进行保护性拷贝


    4.原子更新引用类型

    原子更新多个变量可以使用原子引用类型,提供了3个类:

    • AtomicReference<E>:原子更新引用类型
    • AtomicStampReference<E>:原子更新带版本号的引用类型,可用于原子更新数据和数据的版本号,可以解决ABA问题
    • AtomicMarkableReference<E>:原子更新带有标记位的引用,可以原子更新一个boolean标记位和引用类型
      • 构造方法AtomicMarkableReference(V initialRef,boolean initialMark)
      • 可以通过标记位得知更新前是否修改,解决ABA问题

    使用方式:以AtomicReference为例

    @Test
    public void AtomicReferenceTest(){
        AtomicReference<User> atomicUserRef = new AtomicReference<User>();
        User user=new User("kenshine",23);
        atomicUserRef.set(user);    //set设置
        User newUser=new User("kun",22);
        atomicUserRef.compareAndSet(user,newUser);      //compareAndSet原子更新
        System.out.println(atomicUserRef.get().getName());  //kun get获取
        System.out.println(user.getName());     //kenshine
    }
    
    • set(user),compareAndSet(user,newUser),get()

    5.原子更新字段类

    原子更新某个类的某个字段,需要使用原子更新字段类(3个):

    • AtomicIntegerFieldUpdater<E>:原子更新整型字段
    • AtomicLongFieldUpdater<E>:原子更新长整型字段
    • AtomicReferenceFieldUpdater<T,V>:原子更新引用类型的字段

    原子更新字段类需要两步:

    • 必须使用静态方法newUplodater()创建一个更新器,并设置想要更新的类和属性
    • 更新类的字段必须使用public volatile修饰

    使用方式:

    @Test
    public void AtomicReferTest(){
            //创建newUpdater
            AtomicReferenceFieldUpdater updater=AtomicReferenceFieldUpdater.newUpdater(Dog.class,String.class,"name");
            Dog dog1=new Dog();
            System.out.println(updater.compareAndSet(dog1,"dog1","compareAndSet"));
            System.out.println(dog1.name);
            System.out.println(updater.getAndSet(dog1, "getAndSet"));
            System.out.println(dog1.name);
    }
    class Dog  {
        //必须使用volatile修饰
        volatile String name="dog1";
    }
    

  • 相关阅读:
    记录一次线上优化流程
    php ignite 使用问题记录
    invalid contrller specified 错误分析及解决
    koa 2 的 async 和 await 语法
    koa 2 的安装
    vue 自定义组件 v-model双向绑定、 父子组件同步通信的多种写法
    VS2019专业版和企业版激活密钥
    RE:ゼロから始める PKU 生活 episode 2
    CSP-S 2020 游记
    ioi2021集训队作业
  • 原文地址:https://www.cnblogs.com/kenshine/p/14520619.html
Copyright © 2020-2023  润新知