原子类
基本原子类
AtomicInteger
AtomicLong
AtomicBoolean
java
// 获取当前值
public final int get()
// 获取当前的值,并设置新的值
public final int getAndSet(int newValue)
// 获取当前的值并自增
public final int getAndIncrement()
// 获取当前的值并自减
public final int getAndDecrement()
// 获取当前的值并加上预期的值
public final int getAndAdd(int delta)
// CAS 输入值等于预期值,则以原子方式将新值设置入目标值
public final boolean compareAndSet(int expect, int update)
使用 CountDownLatch 计数器判断所有线程执行完毕
java
class MyNumber //资源类
{
AtomicInteger atomicInteger = new AtomicInteger();
public void addPlusPlus() {
atomicInteger.getAndIncrement();
}
}
public class AtomicIntegerDemo {
public static final int SIZE = 50;
public static void main(String[] args) {
MyNumber myNumber = new MyNumber();
CountDownLatch countDownLatch = new CountDownLatch(SIZE);
for (int i = 0; i < SIZE; i++) {
new Thread(() -> {
try {
for (int j = 1;j <= 1000; j++) {
myNumber.addPlusPlus();
}
}finally {
countDownLatch.countDown();
}
},String.valueOf(i)).start();
}
// 采用 countDownLatch 等待所有线程执行完再执行主线程
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "result:" + myNumber.atomicInteger.get());
}
}
数组原子类
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
引用类型原子类
AtomicReference
原子引用类 CAS 解决线程安全
java
public static void main(String[] args) {
AtomicReference<User> atomicReference = new AtomicReference<>();
User z3 = new User("z3", 22);
User li4 = new User("li4", 23);
atomicReference.set(z3);
//true---User(userName=li4, age=23) 第一次 CAS 修改成功
//false---User(userName=li4, age=23) 第二次 CAS 修改失败
System.out.println(atomicReference.compareAndSet(z3,li4)
+ "---" + atomicReference.get().toString());
System.out.println(atomicReference.compareAndSet(z3,li4)
+ "---" + atomicReference.get().toString());
}
AtomicStampedReference
带戳记流水的原子引用类,标记版本号,解决 ABA 修改过几次的问题
java
@Data
@AllArgsConstructor
class Book{
private int id;
private String bookName;
}
public class AtomicStampedDemo {
public static void main(String[] args) {
Book javaBook = new Book(1, "javaBook");
AtomicStampedReference<Book> stampedReference = new AtomicStampedReference<>(javaBook, 1);
System.out.println(stampedReference.getReference().toString() + " " + stampedReference.getStamp());
Book mysqlBook = new Book(2, "mysqlBook");
boolean b;
b = stampedReference.compareAndSet(javaBook, mysqlBook, stampedReference.getStamp(), stampedReference.getStamp() + 1);
System.out.println(b + " " +stampedReference.getReference() + " " + stampedReference.getStamp());
b = stampedReference.compareAndSet(mysqlBook, javaBook, stampedReference.getStamp(), stampedReference.getStamp() + 1);
System.out.println(b + " " +stampedReference.getReference() + " " + stampedReference.getStamp());
}
//Book(id=1, bookName=javaBook) 1
//true Book(id=2, bookName=mysqlBook) 2
//true Book(id=1, bookName=javaBook) 3
}
AtomicMarkableReference
原子标记引用类型,解决 ABA 问题,是否被修改过
java
public class AtomicMarkableReferenceDemo {
static AtomicMarkableReference markableReference = new AtomicMarkableReference(100,false);
public static void main(String[] args) {
new Thread(()->{
boolean marked = markableReference.isMarked();
//t1默认标识false
System.out.println(Thread.currentThread().getName() + "默认标识" + marked);
TimeUnit.SECONDS.sleep(1);
markableReference.compareAndSet(100,1000,marked,!marked);
},"t1").start();
new Thread(()->{
boolean marked = markableReference.isMarked();
//t2默认标识false
System.out.println(Thread.currentThread().getName() + "默认标识" + marked);
TimeUnit.SECONDS.sleep(2);
// false 因为 t1线程修改过,该标识已经改变,t2 无法修改了
boolean b = markableReference.compareAndSet(100, 2000, marked, !marked);
// 1000 结果为线程 1 改为的 1000
System.out.println(markableReference.getReference());
},"t2").start();
}
}
对象属性修改原子类
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
AtomicReferenceFieldUpdater
- 传统方式使用
synchronized
对转账操作进行线程安全处理粒度太粗,是对象锁 - 使用
AtomicIntegerFieldupdater
对金额变量进行细粒度加锁,更轻量化,性能更高
java
class BankAccount {
String bankName = "CCB";
public volatile int money = 0;
// 1. 传统方式
public synchronized void add() {
money++;
}
// 2. 使用 AtomicIntegerFieldupdater 对 money 字段细粒度加锁
public void transMoney(BankAccount bankAccount) {
fieldUpdater.getAndIncrement(bankAccount);
}
AtomicIntegerFieldUpdater fieldUpdater = AtomicIntegerFieldUpdater
.newUpdater(BankAccount.class, "money");
}
public static void main(String[] args) throws Exception{
BankAccount bankAccount = new BankAccount();
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
for (int j = 0; j < 10000; j++) {
// bankAccount.add();
bankAccount.transMoney(bankAccount);
}
}finally {
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
}
- 使用
AtomicReferenceFieldUpdater
引用类型属性进行细粒度加锁
java
import java.util.concurrent.TimeUnit;
class MyVar { //资源类
public volatile Boolean isInit = Boolean.FALSE;
AtomicReferenceFieldUpdater<MyVar, Boolean> referenceFieldUpdater =
AtomicReferenceFieldUpdater.newUpdater(MyVar.class, Boolean.class, "isInit");
public void init(MyVar myVar) {
if (referenceFieldUpdater.compareAndSet(myVar, Boolean.FALSE, Boolean.TRUE)) {
System.out.println(Thread.currentThread().getName() + "初始化开始,需要 2 秒");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "初始化结束");
} else {
System.out.println(Thread.currentThread().getName() + "已经有其他线程在初始化了");
}
}
}
/**
* 多线程并发调用一个类的初始化方法,如果未被初始化过,将执行初始化工作
要求只能被初始化一次,只有一个线程操作成功
*/
public static void main(String[] args) {
MyVar myVar = new MyVar();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
myVar.init(myVar);
}, "t" + i).start();
}
}
//t2已经有其他线程在初始化了
//t1初始化开始,需要 2 秒
//t0已经有其他线程在初始化了
//t4已经有其他线程在初始化了
//t3已经有其他线程在初始化了
//t1初始化结束
原子增强类
- LongAdder
高并发下,比 AtomicLong 减少乐观锁重试次数,性能更高,但耗费空间也更大;低并发下和 AtomicLong 性能差不多
- LongAccumulator
LongAdder 只能从0开始累加;LongAccumulator 可以指定一个初始值与计算逻辑
java
LongAdder longAdder = new LongAdder();
public void addLongAdder() {
longAdder.increment();
}
LongAccumulator longAccumulator = new LongAccumulator((x,y)->x+y,0);
public void addLongAccumulator() {
longAccumulator.accumulate(1);
}
LongAdder 原理
LongAdder 的基本原理是 分散热点 ,将 Value 值分散到一个 Cell 数组中,不同线程会命中到不同的 Cell 中,减少冲突自旋概率,从而提高并发性能
总结:
- 优先 LongAddr:写入远多于读取的高并发场景
- 优先 AtomicLong:需要频繁读取当前值且对一致性要求较高