Java的原子类
JUC并发包中提供了一系列原子性操作类,这些类都是使用非阻塞算法 CAS 实现的,比使用锁性能有提升。具体实现大致相同。
原子更新基本类型
AtomicBoolean、AtomicInteger、AtomicLong
关键实现代码
public class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");
private volatile long value;
···
}
核心方法
public final boolean compareAndSet(long expectedValue, long newValue) {
return U.compareAndSetLong(this, VALUE, expectedValue, newValue);
}
public final long getAndIncrement() {
return U.getAndAddLong(this, VALUE, 1L);
}
public final long getAndDecrement() {
return U.getAndAddLong(this, VALUE, -1L);
}
public final long incrementAndGet() {
return U.getAndAddLong(this, VALUE, 1L) + 1L;
}
public final long decrementAndGet() {
return U.getAndAddLong(this, VALUE, -1L) - 1L;
}
原子更新数组类型
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
调用构造方法时,会对参数数组拷贝一次。
原子更新引用类型
AtomicReference (存在ABA问题)
AtomicStampedReference(带有时间戳,处理ABA问题)
AtomicMarkableReference(通过添加带有对象是否被修改的boolean值,处理ABA问题)
例子:
public class HelloWorld {
public static void main(String[] args) {
User user1 = new User();
user1.setAge(14);
user1.setName("hello");
AtomicReference<User> userAtomicReference = new AtomicReference<>(user1);
User user2 = new User();
user2.setName("world");
user2.setAge(34);
userAtomicReference.compareAndSet(user1,user2);
System.out.println(userAtomicReference.get());
}
}
class User{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
执行结果
原子更新类字段类型
AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater
优化后的原子操作类
LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator
AtomicLong 类使用 CAS 提供非阻塞原子操作,比起锁已经优化了很多,但使用 AtomicLong 在多线程环境下会造成线程不断自旋尝试(源码使用无限循环),浪费 CPU 资源。为了解决此问题,LongAdder 类在内部维护的多个 Cell 元素来分担对单个变量进行争夺的开销。、
LongAdder 类继承自 Striped64 类,实现序列化。Striped64内部维护着三个变量
volatile long base;//初始值
volatile int cellsBusy;//用来实现自旋锁,状态值 0 与 1
volatile Cell[] cells;//原子可见的Cell元素
底层通过 CAS 算法实现非阻塞原子操作
@sun.misc.Contented//避免Cell数组的伪分享出现,导致降低并发访问的性能
static final class Cell{
volatile long value;
Cell(long x){
value = x;
}
final boolean cas(long cmp,long val){
return UNSAFE.compareAndSwapLong(this,valueOffest,cmp,val);//使用Unsafe类实现对Cell元素操作的原子性
}
}
在 LongAdder 类中维护的变量 cells 采用延迟初始化策略。cells 的元素通过 cas 函数的 CAS 操作达到原子性更新。
public long sum();//返回当前的值,内部所有 cell 和 base 的和,相加时未使用锁,返回值不精确,此时可能有 cell 被修改。多线程有问题。+
public void reset();//重置,base 置0 ,若 cells 的元素有值则置0.
public long sumThenReset(); //累加后置0,多线程有问题。
public long longValue(); //等价与sum();
LongAccumulator(JDK8)
LongAdder 类是 LongAccumulator 的一个特例,LongAccumulator 更加强大。
构造方法:
//当 function 为null时,双目运算器为默认的加法运算器
public LongAccumulator(LongBinaryOperator function, long identify){
this.function = function;
base = this.identify = identify;//可以提供非0的初始值
}
//LongBinaryOperator双目运算器接口
public interface LongBinaryOperator{
long applyAsLong(long left, long right);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。