分类
jdk1.5开始后,rt.jar增加了java.util.concurrent.atomic包,增加了一些专门进行原子操作的类。如下表:
类型 | java类 |
---|---|
原子更新基本类型 | AtomicBoolean |
AtomicInteger | |
AtomicLong | |
原子更新数组 | AtomicIntegerArray |
AtomicLongArray | |
AtomicReferenceArray | |
原子更新引用类型 | AtomicReference |
AtomicStampedReference | |
AtomicMarkableReference | |
原子更新字段类 | AtomicIntegerFieldUpdater |
AtomicLongFieldUpdater | |
AtomicReferenceFieldUpdater | |
累加器 | LongAdder —升级—> LongAccumulator |
DoubleAdder —升级—> DoubleAccumulator |
原子更新基本类型
原子更新类型有:
- AtomicInteger 原子更新整形
- AtomicLong 原子更新长整形
- AtomicBoolean 原子更新bool值
如何使用?这里以AtomicInteger类为例,有两个线程分别对一个整数执行10w次自增1的操作,执行结果期望为20w。如下代码段:
public class AtomicIntegerTest {
private static int num = 0;
private volatile static int flag = 0;
private static AtomicInteger counter = new AtomicInteger(0);
public static void increase(){
num++;
flag++;
counter.getAndIncrement();
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
increase();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
increase();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("num = " + num);
System.out.println("flag = " + flag);
System.out.println("counter = " + counter);
}
}
执行结果:
可见只有类型为AtomicInteger的变量counter结果达到了期望,线程安全。
注意:
1. volatile只能保证jmm的可见性、有序性。
2. 自增操作不是一个原子操作。
原子更新数组
原子更新数组有:
- AtomicIntegerArray:原子更新整形数组里的元素
- AtomicLongArray:原子更新长整形数组里的元素
- AtomicReferenceArray:原子更新引用数组里的元素
如何使用?这里以AtomicIntegerArray类为例,有两个线程分别对数组的第2个元素执行10w次自增1的操作,执行结果期望为20w。如下代码段:
public class AtomicIntegerArrayTest {
private static int[] value = new int[]{1,0,3};
private static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(value);
private static void process(){
for (int i = 0; i < 100000; i++) {
value[1]++;
atomicIntegerArray.incrementAndGet(1);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> process());
Thread t2 = new Thread(() -> process());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("value第二个元素 : " + value[1]);
System.out.println("atomicIntegerArray第二个元素 : " + atomicIntegerArray.get(1));
}
}
执行结果如下:
可见类型为AtomicIntegerArray的变量atomicIntegerArray结果达到了期望,线程安全。
原子更新引用类型
原子更新基本类型是对某一个基本类型(例如,int)进行原子更新。那么一个对象呢,这个对象可能包含多个基本类型的成员变量,这时候就要用到原子更新引用类了。有:
- AtomicReference:原子更新引用类型
- AtomicReferenceFieldUpdater:原子更新引用类型里的字段
- AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法是AtomicMarkableReference(V initialRef,booleaninitialMark)
这个暂时未想到合适应用场景,先学会其用法。有代码段如下:
public class AtomicReferenceTest {
static class Dog {
String name;
String color;
public Dog(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
}
private static Dog value = new Dog("大黄", "yellow");
private static AtomicReference<Dog> atomicReference = new AtomicReference<>(value);
public static void main(String[] args) {
atomicReference.compareAndSet(value, new Dog("小黑", "black"));
System.out.println(atomicReference.get());
}
}
原子更新字段类
包含:
- AtomicIntegerFieldUpdater 原子更新整型字段
- AtomicLongFieldUpdater 原子更新长整型字段
- AtomicReferenceFieldUpdater 原子更新引用类型字段
AtomicIntegerFieldUpdater该类上注释翻译
一种基于反射的实用程序,可实现原子更新指定类的指定 {@code volatile int} 字段。此类设计用于原子数据结构,其中同一个节点的几个字段独立受原子更新。
请注意,{@code compareAndSet} 的保证此类中的方法比其他原子类中的方法弱。因为这个类不能保证该字段的所有使用适用于原子访问的目的,它可以仅保证其他调用的原子性
{@code compareAndSet} 和 {@code set} 在同一个更新程序上。
把一个对象的普通变量升级为原子变量。如何用呢?这里以AtomicIntegerFieldUpdater为例,有如下代码段:
public class AtomicIntegerFieldUpdaterTest {
static Animal dog;
static Animal cat;
static class Animal {
String name;
volatile int age; // 必须被 public volatile修饰
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
private static AtomicIntegerFieldUpdater<Animal> updater
= AtomicIntegerFieldUpdater.newUpdater(Animal.class, "age");
public static void main(String[] args) throws InterruptedException {
dog = new Animal("大黄", 0);
cat = new Animal("招财", 0);
Runnable runnable = () -> {
for (int i = 0; i < 10000; i++) {
dog.age++;
updater.getAndIncrement(cat);
}
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(dog.toString());
System.out.println(cat.toString());
}
}
执行结果:
注意:
Animal 类的age属性必须是整型,且被volatile修饰
累加器
包含下面4个类:
- LongAdder —升级—> LongAccumulator
- DoubleAdder —升级—> DoubleAccumulator
AtomicLong 应用了cas;
LongAdder 应用分段cas,牺牲内存空间,多分配了value变量(Cell[]数组),减少自旋空转频率概率,提高处理性能;
LongAccumulator 一种更广泛的分段cas。LongAdder可以理解为LongAccumulator的一种具体形式。如果LongAccumulator的构造器第一个参数的函数为Long::sum 且执行accumulate(1) ,即,对1的累加。此时LongAccumulator 和 LongAdder功能是一样的。
如何使用呢?我们已LongAdder和LongAccumulator为例,有代码段如下:
public class LongAccumulatorTest {
private static AtomicInteger num = new AtomicInteger(0);
private static LongAdder flag = new LongAdder();
private static LongAccumulator counter = new LongAccumulator(Long::sum, 0);
private static void increment(){
num.getAndIncrement(); // 可注释掉下面两行,查看执行时间
flag.increment(); // 可注释掉上下两行,查看执行时间
counter.accumulate(1);
}
private static Thread createThread(){
return new Thread(() -> {
for (int i = 0; i < 100000; i++) {
increment();
}
});
}
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Thread t1 = createThread();
Thread t2 = createThread();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("num=" + num + ",flag=" + flag + ",counter=" + counter);
System.out.println("共耗时:" + (System.currentTimeMillis() - start) + "ms");
}
注释上面代码increment()方法体的后两行。执行结果如下:
注释上面代码increment()方法体的前后两行。执行结果如下:
注释上面代码increment()方法体的前两行。执行结果如下:
LongAdder 比 AtomicLong 执行快;
LongAccumulator 比 LongAdder 更灵活,实例化时可以传入自定义函数。应用范围更广。