什么是原子变量?
Jdk1.5 后 java.util.concurrent.atomic 包下提供了常用的原子变量
1.volatile保证内存可见性
2. CAS(Compare-And-Swap)算法保证数据的原子性
CAS 算法是硬件对于并发操作共享数据的支持。
CAS包含三个操作数:
内存值 V
预估值 A
更新值 B
并且仅当V==A时,V=B。否则将不做任何操作
简单模拟CAS算法
public class TestCompareAndSwap {
public static void main(String[] args) {
//实例化CAS方法类
final CompareAndSwap cas = new CompareAndSwap();
//循环创建10个线程并发执行模拟CAS方法
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int expectedValue = cas.get();
boolean b = cas.compareAndSet(expectedValue, (int) (Math.random() * 101));
//成功打印true 失败打印false
System.out.println(b);
}
}).start();
}
}
}
//模拟CAS算法类
class CompareAndSwap {
//我们要去操作的这个数
private int value;
//去获取内存中我们要操作的数的值,即value的值。
public synchronized int get() {
return value;
}
//拿期望值跟当前内存中的值作比较 如果期望值==内存中的值 则把新值赋给value 无论成功赋值与否 都返回oldValue
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = this.value;
if (oldValue == expectedValue) {
this.value = newValue;
}
return oldValue;
}
//代用compareAndSwap(int expectedValue, int newValue)方法执行成功则返回true 失败返回false
public synchronized boolean compareAndSet(int expectedValue, int newValue) {
return expectedValue == compareAndSwap(expectedValue, newValue);
}
}
怎么使用原子变量
上篇我们提到的++操作的例子中volatile关机字无法保证数据操作原子性的问题,这里使用原子变量就能很好的解决这个问题。
java.util.concurrent.atomic包下提供了多种原子变量类型,它的使用办法和我们基本数据类型的包装类类似。
public class TestAtomicDemo {
public static void main(String[] args) {
AtomicDemo ad = new AtomicDemo();
for (int i = 0; i <10 ; i++) {
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable {
//把serialNumber生命成AtomicInteger类型
private AtomicInteger serialNumber = new AtomicInteger(0);
@Override
public void run() {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(getSerialNumber());
}
//get方法
public int getSerialNumber() {
//这里就不能用原来的++方法,而是替换成AtomicInteger自带的getAndIncrement()方法实现读取并自增1
return serialNumber.getAndIncrement();
}
}
这样当多个线程并发去操作serialNumber的时候,只有一个线程可以操作成功。失败的线程会在失败后继续请求直到请求成功。也就是循环使用CAS算法。