【多线程与并发】Java中的12个原子操作类
从JDK1.5开始,Java提供了 根据变量类型的不同,Atomic包中的这12个原子操作类可以分为4种类型: 原子更新基本类型类使用原子的方式更新基本类型,Atomic包提供了以下3个类: int addAndGet(int delta) 以原子方式将AtomicInteger的value设置为:delta + 原value,返回更新后的值(即delta + 原value) boolean compareAndSet(int expect,int update) 以原子的方式,如果AtomicInteger的当前值是expect,则将AtomicInteger的值设置为update int getAndIncrement() 以原子的方式将AtomicInteger的当前值加1,注意:返回的是加1前的值 void lazySet(int newValue) 最终将AtomicInteger设置为newValue(使用lazySet设置值后,其他线程可能在之后的一段时间内还是可以读到旧的值) int getAndSet(int newValue) 以原子的方式将AtomicInteger设置为newValue
基本使用方式示例: public void test(){ Executor executor = Executors.newFixedThreadPool(3); AtomicInteger atomicInteger = new AtomicInteger(0); for(int i = 0; i < 10; i++){ executor.execute(()->{ System.out.println("atomicInteger的当前值:" + atomicInteger.addAndGet(1)); }); } } //输出如下(输出顺序可能不同,但结果一定是正确的) atomicInteger的当前值:1 atomicInteger的当前值:2 atomicInteger的当前值:4 atomicInteger的当前值:5 atomicInteger的当前值:3 atomicInteger的当前值:7 atomicInteger的当前值:6 atomicInteger的当前值:9 atomicInteger的当前值:8 atomicInteger的当前值:10
其内部实现原子操作的原理是通过 原子更新数组通过原子的方式更新数组里的某个元素,Atomic包提供了以下3个类:
int addAndGet(int i,int delta) 以原子的方式将数组中i位置处的元素值加上delta,返回:i位置处的元素的旧值+ delta boolean compareAndSet(int i,int expect,int update) 如果当前值等于预期值(数组i位置处的元素),则以原子的方式将数组i位置处的元素值设置为update
使用示例: public void testAtomicIntegerArray() { int[] originArray = new int[]{1,2,3}; AtomicIntegerArray array = new AtomicIntegerArray(originArray); array.getAndSet(0,8); System.out.println(array.get(0)); System.out.println(originArray[0]); } //输出结果: 8 1 ----注意这里,构造方法中是将原数组复制了一份,所以对AtomicIntegerArray的操作,不会影响原数组
原子更新引用类型如果要原子更新多个变量,就需要使用原子更新引用类型,Atomic提供了3个类: 以 class AtomicReferenceExample{ private AtomicReference<User> userAtomicReference = new AtomicReference<>(); @Test public void test(){ User originUser = new User(18,"小岳"); userAtomicReference.set(originUser); User updateUser = new User(28,"老岳"); userAtomicReference.compareAndSet(originUser,updateUser); System.out.println(userAtomicReference.get().getName() + ":" + userAtomicReference.get().getAge()); } class User{ private String name; private int age; public User(int age,String name){ this.name = name; this.age = age; } public int getAge() { return age; } public String getName() { return name; } } } //输出结果如下 老岳:28
原子更新字段类如果需要原子地更新某个类里的某个字段,就需要使用原子更新字段类,Atomic包提供了一下3个类进行原子字段更新。 使用更新字段类必须使用静态方法 以 class AtomicIntegerFieldUpdaterExample{ private AtomicIntegerFieldUpdater<User> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(User.class,"age"); @Test public void test(){ User user = new User(18,"小岳"); fieldUpdater.addAndGet(user,10); System.out.println("user现在的年龄:" + fieldUpdater.get(user)); } class User{ private String name; public volatile int age; public User(int age,String name){ this.name = name; this.age = age; } public int getAge() { return age; } public String getName() { return name; } } } //输出结果如下 user现在的年龄:28
理解循环CASJava中可以通过两种方式来实现原子操作:加锁和循环CAS。 //原子操作类AtomicInteger的incrementAndGet实现(最新源码已非如此,但思想是一致的) public final int incrementAndGet() { for (;;) {//一直循环 int current = get();//取出AtomicInteger当前的内存值 int next = current + 1;//要设置的新值 if (compareAndSet(current,next)){//用CAS操作更新AtomicInteger return next; } } }
参考内容全部来自《Java并发编程的艺术》以及上述书籍作者的聊聊并发(五)——原子操作的实现原理。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |