第7章 Java的13个原子操作类
原子更新基本数据类型
AtomticBoolean AtomicInteger AtomicLong
AtomicInteger aint = new AtomicInteger(10);
aint.incrementAndGet(); //原子方式将当前值加1,返回自增后的 ++i
aint.decrementAndGet(); //原子方式将当前值减1,返回自减后的 --i
aint.getAndIncrement(); //返回自增前的 i++
aint.getAndDecrement();
aint.addAndGet(5);
aint.addAndGet(-5) ;
aint.compareAndSet(17, 5); //如果输入的值等于预期值,返回true,并原子的方式设置为输入值
aint.get(); //获取当前值
原子更新数组
AtomicIntegerArray AtomicLongArray AtomicReferenceArray
int[] values = new int[]{1,2,3,4,5};
AtomicIntegerArray ai = new AtomicIntegerArray(values);
System.out.println(ai.addAndGet(0, 2)); //3
System.out.println(ai.getAndIncrement(1)); //2
System.out.println(values[0]); //1
AtomicIntegerArray 的操作和AtomicInteger是类似的,只是多传递了一个index。
注意:数组values通过构造方法传递进去,AtomicIntegerArray 会根据数组复制一份。所以AtomicIntegerArray内部数组进行修改的时候,不会影响原先的数组。
原子更新引用类型
AtomicReference 原子更新引用类型
AtomicReferenceFieldUpdate:原子更新引用类型里的字段。
AtomicMarkableReference:原子更新带有标记位的引用类型。
AtomicReference<User> auser = new AtomicReference<AtomicTest.User>();
User user = new User("mm", "hangzhou", 5);
auser.set(user); //原子方式设置对象
System.out.println("new name: "+auser.get().getName()); //原子方式获取对象
System.out.println("new age: "+auser.get().getAge());
User useru = new User("dd", "ningbo", 15);
User old = auser.getAndSet(useru); //获取原有对象,设置新的对象。
System.out.println("old name: "+old.getName());
System.out.println("update name: "+auser.get().getName());
System.out.println("update age: "+auser.get().getAge());
auser.compareAndSet(useru, new User("", "", 0));
如果对useru对象进行改变,auser对应数据也会发生改变。与AtomicIntegerArray不同,AtomicReference与原先的对象是绑定的。同时发生变化。
AtomicReferenceFieldUpdater<User, String> nameUp = AtomicReferenceFieldUpdater.newUpdater(User.class, String.class,"name" );
nameUp.compareAndSet(useru, "dd", "ddd");
System.out.println(useru.getName());
AtomicReferenceFieldUpdater初始化要求传入三个参数:字段所属的对象Class,字段Class,字段名。
基于反射。要求字段必须是volatile修饰,并且不能是private
AtomicMarkableReference<User> amuser = new AtomicMarkableReference<AtomicTest.User>(user, false);
amuser.set(useru, true);
System.out.println(amuser.getReference().getName());
AtomicMarkableReference和AtomicReference相比增加了个boolean类型的标记位。
static class User{
public volatile String name;
public volatile String addr;
public volatile int age;
}
为了避免CAS过程中的ABA问题,并发包提供了两个类,AtomicStampedReference和AtomicMarkableReference。前者相当于一个[引用,integer]的二元组,后者相当于一个[引用,boolean]的二元组。
AtomicStampedReference可用来作为带版本号的原子引用,而AtomicMarkableReference可用于表示如:已删除的节点。
注:ABA问题是指在CAS操作过程中,假设我们想要把目标值由1改为2,一般过程是检测目标值是否为1,如果为1就将其设置为2。但可能在检测之前目标值变成了3,然后又变成了1,检测过程并不能察觉到这种变化。这一般不会有什么影响,但在某些情况下也可能会是一个问题。
原子更新字段类型
AtomicIntegerFieldUpdate:原子更新整形的字段的更新器
AtomicLongFieldUpdate:
AtomicStampedReference: 原子更新带有版本号的引用类型。