jdk提供了原子性的数据类型。
//主要有
// AtomicInteger;
// AtomicBoolean;
// AtomicLong;
AtomicInteger ai = new AtomicInteger();
System.out.println(ai);
System.out.println(ai.get());
int i1 = ai.getAndIncrement();//获取并自增
int i2 = ai.incrementAndGet();//自增后获取
int i3 = ai.getAndDecrement();//获取后自减
int i4 = ai.decrementAndGet();//自减后获取
System.out.println(i1);
System.out.println(i2);
System.out.println(i3);
System.out.println(i4);
//输出
//0
//0
//0
//2
//2
//0
AtomicInteger integer = new AtomicInteger(2);
System.out.println("获取并添加:"+integer.getAndAdd(10));
System.out.println("添加并获取:"+integer.addAndGet(10));
integer.set(1);
System.out.println(integer);
System.out.println("获取并设置值:"+integer.getAndSet(2));
System.out.println("添加并获取:"+integer.getAndUpdate(x->x+1));
//输出:
//获取并添加:2
//添加并获取:22
//1
//获取并设置值:1
//添加并获取:2
CAS算法
CAS,即 Compare And Swap(比较与交换),是一种无锁算法,基于硬件原语实现,能够在不使用锁的情况下实现多线程之间的变量同步。jdk中的java.util.concurrent.atomic包中的原子类就是通过CAS来实现了乐观锁。
CAS算法过程
算法涉及到三个操作数:
- 需要读写的内存位置V
- 需要进行比较的预期值A
- 需要写入的新值U
CAS算法解析:
CAS具体执行时,当且仅当预期值A符合内存地址V中存储的值时,就用新值U替换掉旧值,并写入到内存地址V中。否则不做更新。
CAS算法的运行原理如下如所示:
CAS会有如下三个方面的问题:
1.ABA问题,一个线程将内存值从A改为B,另一个线程又从B改回到A。
2.循环时间长开销大:CAS算法需要不断地自旋来读取最新的内存值,长时间读取不到就会造成不必要的CPU开销。
- 只能保证一个共享变量的原子操作(jdk的AtomicReference来保证应用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作,解决了这一问题)。
ABA问题图解:
ABA问题解决方案:在变量前面添加版本号,每次变量更新的时候都将版本号加1,比如juc的原子包中的AtomicStampedReference类。
Java代码模拟CAS算法
这里使用synchronized线程锁关键字模拟硬件操作原语。
package com.initit.j3_juc;
import java.util.Random;
/**
* 模拟cas算法 CompareAndSwap 比较和交换算法
*
* 算法涉及到三个操作数:
*
* 需要读写的内存位置V
* 需要进行比较的预期值A
* 需要写入的新值U
* CAS算法解析:
*
* CAS具体执行时,当且仅当预期值A符合内存地址V中存储的值时,就用新值U替换掉旧值,并写入到内存地址V中。否则不做更新。
*
* @author : liupeng
* @email : 1029538990@qq.com
* @date : 2020/5/23 11:02 下午
*/
public class CASDemo {
static final CompareAndSwap cas = new CompareAndSwap();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
int expectedValue = cas.get();
boolean b = cas.compareAndSet(expectedValue, new Random(100).nextInt());
System.out.println(b);
}).start();
}
}
}
class CompareAndSwap {
private int value;
//获取内存值
public synchronized int get() {
return value;
}
/**
* 比较并设置值
*
* @param expectedValue 期望值
* @param newValue 新值
* @return boolean 设置成功返回true
*/
public synchronized boolean compareAndSet(int expectedValue, int newValue) {
return expectedValue == compareAndSwap(expectedValue, newValue);
}
/**
* 比较和替换
* 期望值跟新值一致时替换,否则不作任何操作
*
* @param expectedValue 期望值
* @param newValue 新值
* @return int 替换后的值
*/
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (oldValue == expectedValue) {
this.value = newValue;
}
return oldValue;
}
}