本文共 4208 字,大约阅读时间需要 14 分钟。
方便程序员在多线程环境下,无锁的进行原子操作
Atomic包里的类基本都是使用Unsafe实现的包装类,核心操作是CAS原子操作;
compare and swap,比较和替换技术,将预期值与当前变量的值比较(compare),如果相等则使用新值替换(swap)当前变量,否则不作操作;
现代CPU已广泛支持CAS指令,如果不支持,那么JVM将使用自旋锁,与互斥锁一样,两者都需先获取锁才能访问共享资源,但互斥锁会导致线程进入睡眠,而自旋锁会一直循环等待直到获取锁;
另外,有一点需要注意的是CAS操作中的ABA问题,即将预期值与当前变量的值比较的时候,即使相等也不能保证变量没有被修改过,因为变量可能由A变成B再变回A,解决该问题,可以给变量增加一个版本号,每次修改变量时版本号自增,比较的时候,同时比较变量的值和版本号即可;
以下三个类是以原子方式更新基本类型
以AtomicInteger为例,
package concurrency;import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerTest { static AtomicInteger ai = new AtomicInteger(1); public static void main(String[] args) { //相当于i++,返回的是旧值,看方法名就知道,先获取再自增 System.out.println(ai.getAndIncrement()); System.out.println(ai.get()); //先自增,再获取 System.out.println(ai.incrementAndGet()); System.out.println(ai.get()); //增加一个指定值,先add,再get System.out.println(ai.addAndGet(5)); System.out.println(ai.get()); //增加一个指定值,先get,再set System.out.println(ai.getAndSet(5)); System.out.println(ai.get()); }}
注意:Atomic包提供了三种基本类型的原子更新,剩余的Java的基本类型还有char,float和double等,其更新方式可以参考AtomicBoolean的思路来现,AtomicBoolean是把boolean转成整型再调用compareAndSwapInt进行CAS来实现的,类似的short和byte也可以转成整形,float和double可以利用Float.floatToIntBits,Double.doubleToLongBits转成整形和长整形进行相应处理;
以下三个类是以原子方式更新数组,
以AtomicIntegerArray为例,其方法与AtomicInteger很像,多了个数组下标索引;
package concurrency;import java.util.concurrent.atomic.AtomicIntegerArray;public class AtomicIntegerArrayTest { static int[] valueArr = new int[] { 1, 2 }; //AtomicIntegerArray内部会拷贝一份数组 static AtomicIntegerArray ai = new AtomicIntegerArray(valueArr); public static void main(String[] args) { ai.getAndSet(0, 3); //不会修改原始数组value System.out.println(ai.get(0)); System.out.println(valueArr[0]); }}
以下三个类是以原子方式更新引用,与其它不同的是,更新引用可以更新多个变量,而不是一个变量;
以AtomicReference为例,
package concurrency;import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceTest { public static AtomicReferenceatomicUserRef = new AtomicReference (); public static void main(String[] args) { User user = new User("conan", 15); atomicUserRef.set(user); User updateUser = new User("Shinichi", 17); atomicUserRef.compareAndSet(user, updateUser); System.out.println(atomicUserRef.get().getName()); System.out.println(atomicUserRef.get().getOld()); } static class User { private String name; private int old; public User(String name, int old) { this.name = name; this.old = old; } public String getName() { return name; } public int getOld() { return old; } }}
以下三个类是以原子方式更新字段,
以AtomicIntegerFieldUpdater为例,
package concurrency;import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;public class AtomicIntegerFieldUpdaterTest { private static AtomicIntegerFieldUpdatera = AtomicIntegerFieldUpdater .newUpdater(User.class, "old"); public static void main(String[] args) { User conan = new User("conan", 10); System.out.println(a.getAndIncrement(conan)); System.out.println(a.get(conan)); } public static class User { private String name; //注意需要用volatile修饰 public volatile int old; public User(String name, int old) { this.name = name; this.old = old; } public String getName() { return name; } public int getOld() { return old; } }}