zoukankan      html  css  js  c++  java
  • 并发编程(十四):原子操作类


    学习资料

    《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";
    }
    

  • 相关阅读:
    java里如何实现对数组中的元素反转[4, 1, 8, 7, 3, 8, 2]变成 [2, 8, 3, 7, 8, 1, 4]
    牛客网Java刷题知识点之插入排序(直接插入排序和希尔排序)、选择排序(直接选择排序和堆排序)、冒泡排序、快速排序、归并排序和基数排序(博主推荐)
    [转]ASP.NET Web API对OData的支持
    [转]Work With Odata in Web API: Create Your First Odata Service
    [转]如何在 .Net Framework 4.0 项目上使用 OData?
    [转]Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)
    [转]使用WCF 4.0 构建 REST Service
    [转]构建基于WCF Restful Service的服务
    [转]asp.net5中使用NLog进行日志记录
    [转]浅谈 .NET Framework 与 .NET Core 的区别与联系
  • 原文地址:https://www.cnblogs.com/kenshine/p/14520619.html
Copyright © 2011-2022 走看看