并发编程(十四):原子操作类
学习资料
《Java并发编程的艺术》第7章
1.原子类简介
java5提供了java.util.concurrent.atomic包,该包的原子操作提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,共12个类
Atomic包里的类基本上都是使用Unsafe实现的包装类
2.原子更新基本类型
使用原子的方式更新基本类型三个类:AtomicBoolean
,AtomicInteger
,AtomicLong
用法几乎一样,AtomicInteger的常用方法如下:
AtomicInteger(n)
:构造方法,将对象内部值初始化为naddAndGet(int n)
:将输入的值n与对象中的值相加并compareAndSet(int expect,int update)
:如果对象中的值为expect,则将其原子地更新为updategetAndIncrement()
:以原子方式加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方法:compareAndSwapObject
、compareAndSwapInt
和compareAndSwapLong
;
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";
}