基本原子类
提供三个:
AtomicInteger
:public class AtomicInteger extends Number implements java.io.Serializable
AtomicLong
:public class AtomicLong extends Number implements java.io.Serializable
AtomicBoolean
:public class AtomicBoolean implements java.io.Serializable
使用方法
public class Main {
public static void main(String[] args) throws InterruptedException {
AtomicLong num = new AtomicLong(0);
for (int i = 0; i < 3; i ++) {
new Thread(() -> {
System.out.printf("[%s]number: %d \n",
Thread.currentThread().getName(), num.addAndGet(100));
}).start();
}
TimeUnit.SECONDS.sleep(1);
System.out.println("get answer: " + num);
}
}
[Thread-0]number: 200
[Thread-1]number: 100
[Thread-2]number: 300
get answer: 300
AtomicLong与AtomicInteger的区别
在AtomicLong
中,比AtomicInteger
多了一部分内容:
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
private static native boolean VMSupportsCS8();
long
是64位的,如果在32位系统中使用long
,long
是由两块32位内存共同组成的,如果对long
做出修改,需要同时对这两块内存同时修改才能完成操作。
addAndGet()
public final long addAndGet(long delta) {
return U.getAndAddLong(this, VALUE, delta) + delta;
}
底层是使用Unsafe
的getAndAddLong()
实现的,这里是由CPU实现的,而不再是Java实现的。好处在于执行速度快,而且避免了数据在内存之中的互相拷贝带来的额外开销。
@HotSpotIntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {
long v;
do {
v = getLongVolatile(o, offset);
} while (!weakCompareAndSetLong(o, offset, v, v + delta));
return v;
}
@HotSpotIntrinsicCandidate
public native long getLongVolatile(Object o, long offset);
@HotSpotIntrinsicCandidate
public final boolean weakCompareAndSetLong(Object o, long offset, long expected, long x) {
return compareAndSetLong(o, offset, expected, x);
}
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetLong(Object o, long offset,long expected,long x);
comareAndSet()
对数据内容进行修改,修改之前会判断当前值是否与期望值excepted
相同,如果相同则修改为x
,否则不允许修改。这是一种乐观锁实现机制。
compareAndset()
数据修改操作方法在JUC中被称为CAS机制,CAS(Compare-And-Swap)是一条CPU并发原语(是CPU的原生指令,是直接写在CPU内部的程序代码)。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,反之则不进行修改,这个过程属于原子性操作。
在多线程进行数据修改时,为了保证数据修改的正确性,常规的做法就是使用synchronized
同步锁,但是这种锁属于悲
观锁(Pessimistic Lock),每一个线程都需要在操作之前锁定当前的内存区域,而后才可以进行处理,这样一来在高并发环境下就会严重影响到程序的处理性能。
而CAS采用的是乐观锁(Optimistic Lock)机制,其最大的操作特点是不进行强制性的同步处理(没有 synchronized
),而为了保证数据修改的正确性,添加了一些比较的数据(例如:compareAndset()
在修改之前需要进行数据的比较),采用的是一种冲突重试的处理机制,这样可以有效的避免线程阻塞问题的出现。在并发竞争不是很激烈的情况下,可以获得较好的处理性能。而在JDK 9后为了进一步提升CAS的操作性能,又追加了硬件处理指令集的支持,可以充分的发挥服务器硬件配置的优势,得到更好的处理性能。
- JDK 9+:
@HotSpotIntrinsicCandidate
- JDK17:
@IntrinsicCandidate
数组原子类
提供三个:
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray<E>
构造方法:
public AtomicIntegerArray(int length)
:初始化数组长度public AtomicIntegerArray(int[] array)
:根据已有数组初始化(深拷贝)
源码:
public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L;
private static final VarHandle AA
= MethodHandles.arrayElementVarHandle(int[].class);
private final int[] array;
compareAndSet()
public final boolean compareAndSet(int i, int expectedValue, int newValue) {
return AA.compareAndSet(array, i, expectedValue, newValue);
}
在原子数组操作类中的CAS机制,在JDK1.7之后不是由Unsafe
提供的,而是由java.lang.invoke
中的VarHandle
提供的。该类主要用于动态操作数组元素或对象的成员属性。VarHandle
类提供了一系列的标准内存屏障操作,用于更细粒度的控制指令排序,在安全性、可用性以及性能方面都要优于已有的程序类库,同时可以和任何类型的变量进行关联操作。
VarHandle
此类是在java.lang.invoke
包下的,顾名思义VarHandle
应该也是一个反射操作类。为什么会有它的出现呢?我们知道,过多的反射机制造成了Java执行困难的问题(JVM导致的),但在VarHandle
里提供了更佳的反射操作。
- JDK1.7-11:
public abstract class VarHandle {
final VarForm vform;
VarHandle(VarForm vform) {
this.vform = vform;
}
- JDK12+:
Constable
常量描述类
public abstract class VarHandle implements Constable {
final VarForm vform;
final boolean exact;
VarHandle(VarForm vform) {
this(vform, false);
}
VarHandle(VarForm vform, boolean exact) {
this.vform = vform;
this.exact = exact;
}
使用VarHandle
实现反射
public class Main {
public static void main(String[] args) throws Exception {
VarHandle varHandle = MethodHandles.lookup()
.findVarHandle(Person.class, "name", String.class);
Person person = Person.class.getDeclaredConstructor().newInstance();
varHandle.set(person, "birdy");
System.out.println(varHandle.get(person));
}
}
MethodHandles
public class MethodHandles {
private MethodHandles() { } // do not instantiate
public static VarHandle arrayElementVarHandle(Class<?> arrayClass) throws Exception {
return VarHandles.makeArrayElementHandle(arrayClass);
}
}
模拟AtomicIntegerArray
实现CAS操作
public class Main {
public static void main(String[] args) throws InterruptedException {
int[] array = new int[] {1,2,3};
VarHandle varHandle = MethodHandles.arrayElementVarHandle(int[].class);
varHandle.compareAndSet(array, 2, 3, 5);
System.out.println(Arrays.toString(array));
}
}