Atomic*
Atomicboolean:原子更新布尔类型
AtomicInteget :原子更新整形
AtomicLong:原子更新长整型
AtomicReference:原子更新引用类型
AtomicStampedReference:原子更新带有版本号的引用类型(可解决ABA问题)
AtomicMarkableReference:原子更新带有标记位的引用类型(可解决ABA问题)
下面以AtomicInteget 为例进行说明:
-
AtomicInteget可以原子更新的整型,不能用作Integer的替换。
源码:
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value; /** * Creates a new AtomicInteger with the given initial value. * * @param initialValue the initial value */ public AtomicInteger(int initialValue) { value = initialValue; } /** * Creates a new AtomicInteger with initial value {@code 0}. */ public AtomicInteger() { } ... }
由上述源码可知这里
value
使用了volatile
关键字进行修饰,由于volatile
关键字会阻止JIT编译优化,导致效率偏低,所以AtomicInteger
类不要随意使用,要在必要的时候使用。 -
可以进行线程安全的递增货递减,用于高并发下原子性递增计数器之类的应用程序中。
下面看一段代码:
package com.hzw.subject1; import java.util.concurrent.atomic.AtomicInteger; public class DemoCounterTest { public static void main(String[] args) throws InterruptedException { final Counter counter = new Counter(); for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 10000; j++) { counter.add(); } System.out.println("done..."); } }).start(); } Thread.sleep(6000L); System.out.println("AtomicInteger i = " + counter.i); System.out.println("int j = " + counter.j); } public static class Counter { AtomicInteger i = new AtomicInteger(0); int j = 0; public void add() { i.getAndIncrement(); j++; } } }
输出结果:
done... done... done... done... done... done... done... done... done... done... AtomicInteger i = 100000 int j = 64994
Atomic*Array
概述
下面以AtomicIntegerArray为例进行说明
AtomicIntegerArray并非由AtomicInteger组成的数组,而是一个普通的int数组,然后可以通过AtomicIntegerArray类提供的方法对int数组的各个数据进行操作。
AtomicIntegerArray array = new AtomicIntegerArray(5);
//array = [0, 0, 0, 0, 0]
array.addAndGet(0, 1);
//array = [1, 0, 0, 0, 0]
array.addAndGet(1, 2);
//array = [1, 2, 0, 0, 0]
//自增并获取
array.incrementAndGet(0);
//array = [2, 2, 0, 0, 0]
//比较并赋值
array.compareAndSet(0, 2, 3);
//array = [3, 2, 0, 0, 0]
分类
AtomicIntegerArray:原子更新整型数组里的元素
AtomicLongArray:原子更新长整型数组里的元素
AtomicReferenceArray:原子更新引用类型数组里的元素
Atomic*FieldUpdater
概述
原子更新器,可以使用更新器对那些非Atomic类型的数据进行Atomic原子操作
分类
AtomicIntegerFieldUpdater :原子更新整形字段的更新器
AtomicLongFieldUpdater :原子更新长整形字段的更新器
AtomicReferenceFieldUpdater :原子更新引用类型字段里的属性的更新器
示例
下面以AtomicIntegerFieldUpdater为例进行说明
package com.hzw.subject1;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class DemoCounterTest {
public static void main(String[] args) throws InterruptedException {
final Counter counter = new Counter();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
counter.add();
}
System.out.println("done...");
}
}).start();
}
Thread.sleep(6000L);
System.out.println("User id = " + counter.user.id);
}
public static class Counter {
AtomicIntegerFieldUpdater<User> atomic = AtomicIntegerFieldUpdater.newUpdater(User.class, "id");
User user = new User(0);
public void add() {
atomic.incrementAndGet(user);
}
}
public static class User{
//必须使用volatile,且字段不可以为私有属性(private)
volatile int id;
public User(Integer id) {
this.id = id;
}
}
}
增强版计数器
概述
当多个线程同时进行计数操作时,会将其分成多个操作单元,不同线程更新不同的单元,只有需要汇总的时候才计算所有单元的累积操作
当进行CAS操作的线程较多时,可能会频繁出现CAS操作失败而进行自旋的问题,从而造成CPU性能的浪费,所以此处将操作分成三个不同的单元,操作完成后在将这三个单元进行求和得出最终的结果
分类
计数器:LongAdder、DoubleAdder,固定每次操作加1
更新器:LongAccumulator、DoubleAccumulator,可以自定义累加规则
示例
package com.hzw.subject1;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
public class LongAdderDemo {
//每次固定+1
static LongAdder adder = new LongAdder();
static AtomicInteger atomicInteger = new AtomicInteger();
//自定义累加规则
static LongAccumulator accumulator = new LongAccumulator((y, x) ->{
return x + y;
}, 0L);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < 2000) {
// adder.increment(); //338761863
// atomicInteger.getAndIncrement();//104186599
accumulator.accumulate(1); //328658167
}
}
}).start();
}
Thread.sleep(3000);
long sum = adder.sum();
System.out.println("sum = " + sum);
System.out.println("atomicInteger = " + atomicInteger);
System.out.println("accumulator = " + accumulator);
}
}
经测试在十个线程累加两秒的情况下LongAdder、LongAccumulator
的累积值为338761863
而AtomicInteger
的累计值为104186599
效率提高了三倍左右