前言
java.util.concurrent.atomic 包下共有 17个类。统计代码如下
public static void main(String[] args) throws IOException {
JarFile jarFile = new JarFile("/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/rt.jar");
Enumeration<JarEntry> jarEntries = jarFile.entries();
AtomicInteger num = new AtomicInteger();
String packageStr = "java/util/concurrent/atomic";
jarFile.stream().forEach(m->{
if(m.getName().startsWith(packageStr) && !m.getName().contains("$") && m.getName().endsWith("class")){
System.out.println(m.getName().substring(m.getName().indexOf(packageStr)+packageStr.length()+1));
num.getAndIncrement();
}
});
System.out.println("共有类:"+num.toString());
结果如下:
包简介
atmic 包主要支持单变量上的无锁线程安全编程。
分类:
- 原子更新基本类型类
- AtomicBoolean:原子更新布尔类型。
- AtomicInteger:原子更新整型。
- AtomicLong:原子更新长整型。
- 原子更新数组类
- AtomicIntegerArray:原子更新整型数组里的元素。
- AtomicLongArray:原子更新长整型数组里的元素。
- AtomicReferenceArray:原子更新引用类型数组里的元素。
- 原子更新引用类型
- AtomicReference:原子更新引用类型。
- AtomicReferenceFieldUpdater:原子更新引用类型里的字段。
- AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
- AtomicLongFieldUpdater:原子更新长整型字段的更新器。
- AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用CAS进行原子更新时,可能出现的ABA问题。
- 针对 Atomic 相关数字类的改进类
- LongAdder
- LongAccumulator
- DoubleAdder
- DoubleAccumulator
原子更新基本类型
AtomicBoolean
常用方法:
- public final boolean compareAndSet(boolean expect,
boolean update)
如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
参数:
expect - 预期值
update - 新值
返回:
如果成功,则返回 true。返回 False 指示实际值与预期值不相等。 - getAndSet
public final boolean getAndSet(boolean newValue)
以原子方式设置为给定值,并返回以前的值。
参数:
newValue - 新值
返回:
以前的值
AtomicInteger
常用方法(如果涉及加减,则只列举加):
- incrementAndGet 自增,返回最新的值
- addAndGet 做加法,并返回最新的值
- compareAndSet 设置值,并返回是否设置成功
AtomicLong
常用方法(如果涉及加减,则只列举加):
- incrementAndGet 自增,返回最新的值
- addAndGet 做加法,并返回最新的值
- compareAndSet 设置值,并返回是否设置成功
原子更新数组类
注意:
- 原子更新数组类不会直接操作传入的数组,而是操作自己 clone 的传入的数组的副本
AtomicIntegerArray
常用方法:
- addAndGet(int i, int delta) cas 更新下标为 i 的数字为 当前数+delta,并返回最新值
- incrementAndGet(int i) cas 下标为 i 的元素进行自增,并返回最新值
- compareAndSet(int i, int expect, int update) 比较下标为 i 的元素和 expect,相等则更新为 update,返回是否更新成功
AtomicLongArray
类似 AtomicIntegerArray
AtomicReferenceArray
常用方法:
- compareAndSet(int i, E expect, E update) 比较下标为 i 的引用和 expect 是否相同,相同的话,则将引用更新为 update。返回值为是否更新
原子更新引用类型
AtomicReference
原子更新引用
AtomicReferenceFieldUpdater
原子更新引用对象字段。这个类是基于反射的一个工具类。被更新的字段需要满足以下要求:
- 被 volatile 修饰(保证可见行)
- 不能被 private 修饰符修饰
核心方法:
- AtomicReferenceFieldUpdater<U,W> newUpdater(Class< U> tclass,
Class< W> vclass,
String fieldName) 生成一个更新器。 - compareAndSet(T obj, V expect, V update) 比较并跟新 obj 的字段值,并返回是否成功更新
使用示例:
@org.junit.Test
public void testAtomicReferenceFieldUpdater(){
Person person = new Person("小田切让",20);
AtomicReferenceFieldUpdater fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Person.class,Integer.class,"age");
fieldUpdater.compareAndSet(person,person.getAge(),new Integer(33));
System.out.println(person.getAge());
}
@AllArgsConstructor
@Data
class Person{
private String name;
public volatile Integer age;
}
AtomicIntegerFieldUpdater
修改引用对象中被 int 修饰的字段。该字段必须满足以下要求:
- 被 int 修饰,不能使用包装类型 Integer 修饰
- 必须被 volatile 修饰
- 不能被 private 修饰
常用方法:
- newUpdater(Class tclass,String fieldName) 生成字段更新器
- incrementAndGet(T obj) obj 的字段自增,并返回最新值
- compareAndSet(T obj, int expect, int update)
示例:
@org.junit.Test
public void testAtomicIntegerFieldUpdater(){
Person person = new Person("小田切让",new Integer(20));
AtomicIntegerFieldUpdater<Person> updater = AtomicIntegerFieldUpdater.newUpdater(Person.class,"age");
updater.incrementAndGet(person);
updater.compareAndSet(person,person.getAge(),new Integer(25));
System.out.println(person.getAge());
}
@AllArgsConstructor
@Data
class Person{
private String name;
public volatile int age;
}
AtomicLongFieldUpdater
类似 AtomicIntegerFieldUpdater ,修改引用对象中被 long 修饰的字段。该字段必须满足以下要求:
- 被 long 修饰,不能使用包装类型 Long 修饰
- 必须被 volatile 修饰
- 不能被 private 修饰
AtomicStampedReference
解决原子更新引用的「ABA」问题
常用方法:
- compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) 比较引用和标志,都相同才进行更新,并返回更新结果
示例:
@org.junit.Test
public void testAtomicStampedReference(){
Person person = new Person("小田切让",20);
AtomicStampedReference<Person> reference = new AtomicStampedReference<>(person,100);
reference.compareAndSet(person,new Person("小栗旬",23),100,101);
System.out.println(reference.getReference().getName());
System.out.println(reference.getStamp());
}
针对 Atomic 相关数字类的改进类
LongAdder
针对 AtomicLong 的改进类,在高并发的情况下,拥有更好的表现
常用方法:
- add(long x) 加法
- increment() 自增
- decrement() 自减
DoubleAdder
常用方法:
- add(double x)
LongAccumulator
LongAdder 只提供了「加」操作,假如需要对当前结果 m 进行 m*5+1,这种复合运算,则需要 LongAccumulator。
ongAdder类是LongAccumulator的一个特例,LongAccumulator提供了比LongAdder更强大的功能,如下构造函数,其中accumulatorFunction是一个双目运算器接口,根据输入的两个参数返回一个计算值(两个参数分别代表,当前值,输入值),identity则是LongAccumulator累加器的初始值。
常用方法:
- LongAccumulator(LongBinaryOperator accumulatorFunction,
long identity) - accumulate(long x) 进行一次计算
demo:
@org.junit.Test
public void testLongAccumulator(){
LongAccumulator longAccumulator = new LongAccumulator((m,n)-> {
return m*n+1; // 这里结果其实是 100 * 10 +1
},100);
longAccumulator.accumulate(10);
System.out.println(longAccumulator.longValue());
}
DoubleAccumulator
类似 LongAccumulator