该栏目讲叙多线程基础、共享模型的内存、管程、无锁、不可变设计和多线程并发工具
CAS机制
1、简介
概述
:CAS,是 Compare and Swap 的简称,即比较并替换,是乐观锁的一种体现优点
- 可以保证变量操作的原子性
- 并发量不是很高的情况下,使用 CAS 机制比使用锁机制效率更高
- 在线程对共享资源占用时间较短的情况下,使用 CAS 机制效率也会较高(synchronized 会让线程在没有获得锁的时候,发生上下文切换,进入阻塞)
缺点
- CPU 开销过大
- 不能保证代码块的原子性
- ABA 问题
2、原理
- 其实 CAS 的底层是 lock cmpxchg 指令(X86架构),在单核 CPU 和多核 CPU 下都能够保证【比较-交换】的原子性
- 在多核状态下,某个核执行到带 lock 的指令时,CPU 会让总线锁住,当这个核把此指令执行完毕,再开启总线。这个过程中不会被线程的调度机制所打断,保证了多个线程对内存操作的准确性是原子的
3、案例
package com.itnear.atomic;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 转账案例
*/
public class AtomicDemo {
private final AtomicInteger balance;
public AtomicDemo(int balance) {
this.balance = new AtomicInteger(balance);
}
/**
* 转账
*
* @param amount 金额
*/
public void withdraw(int amount) {
while (true) {
if (balance.get() <= 0) {
System.out.println("余额不足,转账失败");
break;
}
final int preAmount = balance.get();
final int nextAmount = preAmount - amount;
final boolean flag = balance.compareAndSet(preAmount, nextAmount);
if (flag) {
System.out.println("转账成功,当前余额:" + nextAmount);
break;
}
}
}
/**
* 获取金额
*
* @return 金额
*/
public int getAmount() {
return balance.get();
}
public static void main(String[] args) {
AtomicDemo atomicDemo = new AtomicDemo(10000);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 1010; i++) {
threads.add(new Thread(() -> atomicDemo.withdraw(10)));
}
threads.forEach(Thread::start);
threads.forEach(thread -> {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("余额:" + atomicDemo.getAmount());
}
}
原子整型
public class AtomicIntegerDemo {
private static final AtomicInteger atomicInteger = new AtomicInteger(0);
private static final AtomicLong atomicInteger = new AtomicLong(0);
public static void main(String[] args) {
// 获取并自增
int value = atomicInteger.getAndIncrement();
System.out.println("value = " + value);
// 自增并获取
value = atomicInteger.incrementAndGet();
System.out.println("value = " + value);
// 获取并自减
value = atomicInteger.getAndDecrement();
System.out.println("value = " + value);
// 自减并获取
value = atomicInteger.decrementAndGet();
System.out.println("value = " + value);
// 添加并获取
value = atomicInteger.addAndGet(5);
System.out.println("value = " + value);
// 获取并添加
value = atomicInteger.getAndAdd(5);
System.out.println("value = " + value);
// 更新并获取
value = atomicInteger.updateAndGet(p -> p + 2);
System.out.println("value = " + value);
// 获取并更新
value = atomicInteger.getAndUpdate(p -> p - 2);
System.out.println("value = " + value);
// 获取并计算
value = atomicInteger.getAndAccumulate(10, (p, x) -> p + x);
System.out.println("value = " + value);
// 计算并获取
value = atomicInteger.accumulateAndGet(10, (p, x) -> p - x);
System.out.println("value = " + value);
// 获取
value = atomicInteger.get();
System.out.println("value = " + value);
}
}
原子布尔型
public class AtomicBooleanDemo {
private static final AtomicBoolean atomicBoolean = new AtomicBoolean();
public static void main(String[] args) {
// 获取并设置
boolean flag = atomicBoolean.getAndSet(true);
System.out.println("flag = " + flag);
// 设置
atomicBoolean.set(false);
// 获取
flag = atomicBoolean.get();
System.out.println("flag = " + flag);
}
}
原子引用
public class AtomicReferenceDemo {
public static void main(String[] args) {
referenceTest();
stampedReferenceTest();
markReferenceTest();
}
/**
* AtomicReference类用于对引用类型进行CAS操作,但避免不了ABA问题
*/
private static void referenceTest() {
AtomicReference<BigDecimal> atomicReference = new AtomicReference<>();
// 设置
atomicReference.set(new BigDecimal(10));
// 获取
BigDecimal decimal = atomicReference.get();
System.out.println("decimal = " + decimal);
// 获取并设置
decimal = atomicReference.getAndSet(new BigDecimal(20));
System.out.println("decimal = " + decimal);
}
/**
* AtomicStampedReference可以给原子引用添加版本号,可以引用变量中途被修改了几次,可以解决ABA问题
*/
private static void stampedReferenceTest() {
AtomicStampedReference<String> stampedReference = new AtomicStampedReference<>("A", 0);
// 获取值
final String reference = stampedReference.getReference();
// 获取版本
final int stamp = stampedReference.getStamp();
// 比较并设置
final boolean flag = stampedReference.compareAndSet(reference, "C", stamp, stamp + 1);
if (flag) {
System.out.println("更新成功");
}
}
/**
* AtomicMarkableReference只关心原子引用是否被修改过,也可以解决ABA问题
*/
private static void markReferenceTest() {
AtomicMarkableReference<Integer> markReference = new AtomicMarkableReference<>(10, false);
// 获取值
final Integer reference = markReference.getReference();
// 获取标志
final boolean marked = markReference.isMarked();
// 比较并设置
final boolean flag = markReference.compareAndSet(reference, reference + 1, marked, !marked);
if (flag) {
System.out.println("更新成功");
}
}
}
原子数组
public class AtomicArrayDemo {
private static final AtomicIntegerArray integerArray = new AtomicIntegerArray(11);
private static final AtomicLongArray longArray = new AtomicLongArray(10);
private static final AtomicReferenceArray<BigDecimal> referenceArray = new AtomicReferenceArray<>(10);
public static void main(String[] args) {
// 获取并自增
int value0 = integerArray.getAndIncrement(0);
System.out.println("value0 = " + value0);
// 自增并获取
int value1 = integerArray.incrementAndGet(1);
System.out.println("value1 = " + value1);
// 获取并自减
int value2 = integerArray.getAndIncrement(2);
System.out.println("value2 = " + value2);
// 自减并获取
int value3 = integerArray.decrementAndGet(3);
System.out.println("value3 = " + value3);
// 添加并获取
int value4 = integerArray.addAndGet(4, 5);
System.out.println("value4 = " + value4);
// 获取并添加
int value5 = integerArray.getAndAdd(5, 5);
System.out.println("value5 = " + value5);
// 更新并获取
int value6 = integerArray.updateAndGet(6, p -> p + 2);
System.out.println("value6 = " + value6);
// 获取并更新
int value7 = integerArray.getAndUpdate(7, p -> p - 2);
System.out.println("value7 = " + value7);
// 获取并计算
int value8 = integerArray.getAndAccumulate(8, 10, (p, x) -> p + x);
System.out.println("value8 = " + value8);
// 计算并获取
int value9 = integerArray.accumulateAndGet(9, 10, (p, x) -> p - x);
System.out.println("value9 = " + value9);
// 获取
int value = integerArray.get(10);
System.out.println("value = " + value);
}
}
字段更新器
public class AtomicFixedDemo {
private volatile int value;
private volatile String msg;
public static void main(String[] args) {
integerFieldTest();
referenceFieldTest();
}
/**
* 整形字段更新器
*/
private static void integerFieldTest() {
AtomicIntegerFieldUpdater<AtomicFixedDemo> fieldUpdater =
AtomicIntegerFieldUpdater.newUpdater(AtomicFixedDemo.class, "value");
AtomicFixedDemo fixedDemo = new AtomicFixedDemo();
// 设置
fieldUpdater.set(fixedDemo, 10);
// 获取
final int value = fieldUpdater.get(fixedDemo);
System.out.println("value = " + value);
// 比较并设置
final boolean flag = fieldUpdater.compareAndSet(fixedDemo, value, value + 10);
System.out.println("修改结果:" + flag);
}
/**
* 引用字段更新器
*/
private static void referenceFieldTest() {
AtomicReferenceFieldUpdater<AtomicFixedDemo, String> fieldUpdater =
AtomicReferenceFieldUpdater.newUpdater(AtomicFixedDemo.class, String.class, "msg");
AtomicFixedDemo fixedDemo = new AtomicFixedDemo();
// 设置
fieldUpdater.set(fixedDemo, "Near");
// 获取
final String msg = fieldUpdater.get(fixedDemo);
System.out.println("msg = " + msg);
// 比较并设置
final boolean flag = fieldUpdater.compareAndSet(fixedDemo, msg, "NearJC");
System.out.println("修改结果:" + flag);
}
}
原子累加器
public class LongAdderDemo {
private static final LongAdder longAdder = new LongAdder();
public static void main(String[] args) {
// 自增
longAdder.increment();
// 自减
longAdder.decrement();
// 添加
longAdder.add(10);
// 获取值
final int value1 = longAdder.intValue();
System.out.println("value1 = " + value1);
final double value2 = longAdder.doubleValue();
System.out.println("value2 = " + value2);
}
}