java并发-原子操作类

概述

JUC中提供了16个原子操作类
基本类型原子更新类
java.util.concurrent.atomic.AtomicBoolean 布尔型原子类
java.util.concurrent.atomic.AtomicInteger 整型原子类
java.util.concurrent.atomic.AtomicLong 布尔型原子类
数组类型原子更新类
java.util.concurrent.atomic.AtomicIntegerArray 整型数组原子类
java.util.concurrent.atomic.AtomicLongArray 长整型数组原子类
java.util.concurrent.atomic.AtomicReferenceArray 引用类型数组原子类

引用类型原子更新类
java.util.concurrent.atomic.AtomicReference 引用类型原子类
java.util.concurrent.atomic.AtomicStampedReference原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题
java.util.concurrent.atomic.AtomicMarkableReference 原子更新带有标记位的引用类型
对象的属性修改类型
java.util.concurrent.atomic.AtomicReferenceFieldUpdater 原子更新引用类型里的字段
java.util.concurrent.atomic.AtomicIntegerFieldUpdater 原子更新整性字段更新器
java.util.concurrent.atomic.AtomicLongFieldUpdater 原子更新长整型字段的更新器
高并发类型
java.util.concurrent.atomic.LongAdder
java.util.concurrent.atomic.LongAccumulator
java.util.concurrent.atomic.DoubleAdder
java.util.concurrent.atomic.DoubleAccumulator

基本类型

使用原子的方式更新基本类型

  • AtomicInteger:整型原子类
  • AtomicLong:长整型原子类
  • AtomicBoolean:布尔型原子类
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerTest {
    public static void main(String[] args) {
        int temvalue = 0;
        AtomicInteger i = new AtomicInteger(0);
        temvalue = i.getAndSet(3);
        System.out.println("temvalue:" + temvalue + ";  i:" + i);//temvalue:0;  i:3
        temvalue = i.getAndIncrement();
        System.out.println("temvalue:" + temvalue + ";  i:" + i);//temvalue:3;  i:4
        temvalue = i.getAndAdd(5);
        System.out.println("temvalue:" + temvalue + ";  i:" + i);//temvalue:4;  i:9
    }
}

AtomicInteger 类的部分源码

 // setup to use Unsafe.compareAndSwapInt for updates(更新操作时提供“比较并替换”的作用)
 private static final Unsafe unsafe = Unsafe.getUnsafe();
 private static final long valueOffset;
 static {
     try {
         valueOffset = unsafe.objectFieldOffset
             (AtomicInteger.class.getDeclaredField("value"));
     } catch (Exception ex) { throw new Error(ex); }
 }
 private volatile int value;

AtomicInteger 类主要利用 CAS (compare and swap)+ volatilenative 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。

CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。

数组类型

使用原子的方式更新数组里的某个元素

  • AtomicIntegerArray:整形数组原子类
  • AtomicLongArray:长整形数组原子类
  • AtomicReferenceArray :引用类型数组原子类
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicIntegerArrayTest {
    public static void main(String[] args) {
        int tempvalue = 0;
        int[] nums = {1,2,3,4,5,6};
        AtomicIntegerArray i = new AtomicIntegerArray(nums);
        for (int j = 0; j <nums.length ; j++) {
            System.out.println(i.get(j));
        }
        tempvalue = i.getAndSet(0, 2);
        System.out.println("temvalue:" + tempvalue + ";  i:" + i);
        tempvalue = i.getAndIncrement(0);
        System.out.println("temvalue:" + tempvalue + ";  i:" + i);
        tempvalue = i.getAndAdd(0, 5);
        System.out.println("temvalue:" + tempvalue + ";  i:" + i);
    }
}
import java.util.concurrent.atomic.AtomicReferenceArray;

public class AtomicReferenceArrayTest {
    public static void main(String[] args) {
        AtomicReferenceArray<String> referenceArray = new AtomicReferenceArray<>(2);
        referenceArray.set(0,"java");
        System.out.println(referenceArray.get(0));
        referenceArray.set(1,"C++");
        System.out.println(referenceArray.compareAndSet(1,"world","groovy"));
        System.out.println(referenceArray.get(1));
    }
}

引用类型

基本类型原子类只能更新一个变量,如果需要原子更新多个变量,需要使用引用类型原子类。

  • AtomicReference:引用类型原子类
  • AtomicStampedReference:原子更新引用类型里的字段原子类,用版本戳,可以解决ABA问题
  • AtomicMarkableReference :原子更新带有标记位的引用类型,用布尔值标记
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
    public static void main(String[] args) {
        // AtomicReference
        AtomicReference<User> ar = new AtomicReference<>();
        User person = new User("jack", 22);
        ar.set(person);
        User updatePerson = new User("mic", 20);
        ar.compareAndSet(person, updatePerson);
        System.out.println(ar.get().getName());
        System.out.println(ar.get().getAge());
    }
}
@Data
class User {
    private String name;
    private int age;
}

AtomicStampedReference通过版本号解决ABA问题,如数据库

String str1 = "AAA";
String str2 = "BBB";
AtomicStampedReference<String> reference = new AtomicStampedReference<>(str1,1);
// 如果当前引用等于预期值 并且当前版本戳等于预期版本戳,将更新引用和新的版本戳
reference.compareAndSet(str1,str2,reference.getStamp(),reference.getStamp()+1);
// 返回引用
System.out.println(reference.getReference());
// 返回版本戳
System.out.println(reference.getStamp());
// 如果当前引用 等于 预期引用,将更新新的版本戳
System.out.println(reference.attemptStamp(str2,reference.getStamp()+1));

AtomicMarkableReference 用布尔值进行标记也可以解决ABA问题,只有两个状态

AtomicMarkableReference<String> markableReference = new AtomicMarkableReference<>("jack",true);
System.out.println(markableReference.getReference()+" " +markableReference.isMarked());
// 当前值和预期值相等,重新设置标记
markableReference.attemptMark("jack",false);
System.out.println(markableReference.getReference()+" " +markableReference.isMarked());
// 布尔值 cas
markableReference.compareAndSet("jack","Sandy",true,false);
System.out.println(markableReference.getReference()+" " +markableReference.isMarked());
// 重置
 markableReference.set("rain",true);
System.out.println(markableReference.getReference()+" " +markableReference.isMarked());

对象的属性修改

对象的属性修改类型
java.util.concurrent.atomic.AtomicReferenceFieldUpdater 原子更新引用类型里的字段
java.util.concurrent.atomic.AtomicIntegerFieldUpdater 原子更新整性字段更新器
java.util.concurrent.atomic.AtomicLongFieldUpdater 原子更新长整型字段的更新器

注:更新的对象字段必须要public volatile 修饰

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
public class AtomicReferenceFieldTest {
    public static void main(String[] args) {
        Person person = new Person("jack",18);
        AtomicIntegerFieldUpdater<Person> age = AtomicIntegerFieldUpdater.newUpdater(Person.class,"age");
        age.getAndIncrement(person);
        System.out.println(person.getAge());
        AtomicLongFieldUpdater<Person> lev =  AtomicLongFieldUpdater.newUpdater(Person.class,"lev");
        lev.addAndGet(person,1L);
        System.out.println(person.getLev());
        AtomicReferenceFieldUpdater<Person,String> name = AtomicReferenceFieldUpdater.newUpdater(Person.class,String.class,"name");
        name.getAndSet(person,"mic");
        System.out.println(person.getName());
    }
}

@Data
class Person {
    public volatile String name;
    public volatile  int age;
    public volatile long lev;
}   

高并发类型

在这里插入图片描述
这些类在高并发情况下具有更高的性能,通过数组(Cell)分片思想(ConcurrentHashMap也使用分片思想)达到的,都是继承java.util.concurrent.atomic.Striped64

// Striped64的内部类实现
 @sun.misc.Contended static final class Cell {
        volatile long value;
        Cell(long x) { value = x; }
        final boolean cas(long cmp, long val) {
            return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
        }
        // Unsafe mechanics
        private static final sun.misc.Unsafe UNSAFE;
        private static final long valueOffset;
        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class<?> ak = Cell.class;
                valueOffset = UNSAFE.objectFieldOffset
                    (ak.getDeclaredField("value"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

java.util.concurrent.atomic.LongAdder 只能针对数值的进行加减运算
java.util.concurrent.atomic.LongAccumulator LongAdder的增强版本,提供了自定义函数操作LongBinaryOperator

java.util.concurrent.atomic.DoubleAdder 操作double类型,底层的会将原始的double类型转换为long类
参考:
java.util.concurrent.atomic.DoubleAdder#add 中调用 Double.doubleToRawLongBits方法

java.util.concurrent.atomic.DoubleAccumulator DoubleAdder增强版

LongAdder longAdder = new LongAdder();
longAdder.increment();
System.out.println(longAdder);
// 取最大的值
LongAccumulator longAccumulator = new LongAccumulator(Long::max,1);
longAccumulator.accumulate(10); // 10 > 1, 取 10
System.out.println(longAccumulator.longValue());// 10
longAccumulator.accumulate(9); // 9 < 10, 取10
System.out.println(longAccumulator.longValue()); // 10
DoubleAdder doubleAdder = new DoubleAdder();
doubleAdder.add(2.0);
System.out.println(doubleAdder.doubleValue()); // 2.0
DoubleAccumulator doubleAccumulator = new DoubleAccumulator(Double::sum,0);
doubleAccumulator.accumulate(2.0);
doubleAccumulator.accumulate(3.0);
System.out.println(doubleAccumulator.doubleValue()); // 5.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值