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


学习资料

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

posted @ 2021-03-11 21:18  菜鸟kenshine  阅读(75)  评论(0编辑  收藏  举报