转载自:https://juejin.im/post/5aeec351518825670a103292#heading-2
其余转载内容放在对应段落
java.util.concrrent.atomic包分类
原子更新基本类型 | AtomicBoolean | 以原子更新的方式更新boolean |
AtomicInteger | 以原子更新的方式更新Integer | |
AtomicLong | 以原子更新的方式更新Long | |
原子更新数组类型 | AtomicIntegerArray | 原子更新整型数组中的元素 |
AtomicLongArray | 原子更新长整型数组中的元素 | |
AtomicReferenceArray | 原子更新引用类型数组中的元素 | |
原子更新引用类型 | AtomicReference | 原子更新引用类型 |
AtomicReferenceFieldUpdater | 原子更新引用类型里的字段 | |
AtomicMarkableReference | 原子更新带有标记位的引用类型 | |
原子更新字段类型 | AtomicIntegerFieldUpdater | 原子更新整型字段类 |
AtomicLongFiledUpdater | 原子更新长整型字段类 | |
AtomicStampedReference | 原子更新引用类型,这种更新方式会带有版本号。而为什么在更新的时候会带有版本号,是为了解决CAS的ABA问题 | |
jdk1.8扩展类 | DoubleAccumulator | 四个原理相似,LongAdder和对应的AtomicLong而言性能更高。AtomicLong在高并发场景下CAS可能会导致多个线程自旋,性能消耗太大;LongAdder采用锁分段的思想,在高并发场景下利用创建Cell数组(数组最大长度等于CPU核数),把竞态线程分发到不同的Cell数组分别做CAS处理,减少争用的自旋操作;在get最新值时需要把base值(对象基础值,都在此值上操作)和cell数组中所有的值相加返回;参考https://github.com/aCoder2013/blog/issues/22 |
DoubleAdder | ||
LongAccumulator | ||
LongAdder | ||
Striped64 | 并发计数组件,是上面四个类型(LongAdder)的实现基础,采用Cell数组在高并发场景下将线程分摊到Cell数组中,锁分段减少竞态提高并发性能,相关参考https://www.jianshu.com/p/30d328e9353b |
各种分类的用法
原子更新基本类型
实现机制参考https://blog.csdn.net/jiankangcs/article/details/94588590 这里不做说明
原子更新数组类型
以AtomicIntegerArray为例
/**
* 更新数组元素第i个值并返回更改前的最新值
*/
public final int getAndAdd(int i, int delta) {
// checkedByteOffset(i)获取数组中第i个元素内存偏移位置
return unsafe.getAndAddInt(array, checkedByteOffset(i), delta);
}
// 案例
public class AtomicDemo {
// private static AtomicInteger atomicInteger = new AtomicInteger(1);
private static int[] value = new int[]{1, 2, 3};
private static AtomicIntegerArray integerArray = new AtomicIntegerArray(value);
public static void main(String[] args) {
//对数组中索引为1的位置的元素加5
int result = integerArray.getAndAdd(1, 5);
System.out.println(integerArray.get(1));
System.out.println(result);
}
}
// 输出结果:
// 7
// 2
原子更新引用类型
public class AtomicReferenceTest {
private static AtomicReference<User> reference = new AtomicReference<>();
public static void main(String[] args) {
User user1 = new User("a", 1);
reference.set(user1);
User user2 = new User("b",2);
User user = reference.getAndSet(user2);
System.out.println(user);
System.out.println(reference.get());
System.out.println(user1);
}
static class User {
private String userName;
private int age;
public User(String userName, int age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
}
// 输出结果:
// User{userName='a', age=1}
// User{userName='b', age=2}
// User{userName='a', age=1}
原子更新字段类型
要想使用原子更新字段需要两步操作:
- 原子更新字段类都是抽象类,只能通过静态方法
newUpdater
来创建一个更新器,并且需要设置想要更新的类和属性; - 更新类的属性必须使用
public volatile
进行修饰;
public class AtomicFiledTest {
private static AtomicIntegerFieldUpdater updater = AtomicIntegerFieldUpdater.newUpdater(User.class,"age");
public static void main(String[] args) {
User user = new User("a", 1);
int oldValue = updater.getAndAdd(user, 5);
System.out.println(oldValue);
System.out.println(updater.get(user));
}
static class User {
private String userName;
public volatile int age;
public User(String userName, int age) {
this.userName = userName;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
}
// 1
// 6