概述
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)
+ volatile
和 native
方法来保证原子操作,从而避免 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