一 、 原子性
例子:i++的原子性问题:i++的操作实际上分为三个步骤 “读-改-写”
int i = 10 ;
i = i ++; //i为10
//分为三步
int tmp = 1;
i = i + 1;
i = tmp;
/**
* 原子性
*
* @author xiaobin
* @date 2018/3/3
*/
public class TestAtomic {
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 {
private int serialNumber = 0 ;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + getSerialNumber());
}
public int getSerialNumber() {
return serialNumber++;
}
}
二、原子变量
jdk1.5后 java.util.concurrent.atomic 包下提供了常用的原子变量。
特性
- 有volatile的特性。
以AtomicInteger 为例,内部定义`private volatile int value;。 - CAS(CompareAndSwap)算法保证数据的原子性。
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
Atomic原子变量的操作
- 获取并自增/自减/增加指定值
获取值后如果设置失败将循环设置,直到成功。(这个就是解决i++原子性问题的方法)
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
- 获取并设置。
获取后如果设置失败,将循环设置。
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
三、CAS算法
CAS算法是硬件对于并发操作共享数据的支持。效率要高,但是需要对业务对失败等情况作处理。
包含三个操作数
- 内存值 V
- 预估值 A
- 更新值 B
当且仅当V == A 时,V = B。否则将不做任何操作。实现时,可能更新失败,会进行循环。
例如上面提到的getAndSet
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
如果线程线程1先更新,那么线程2将会更新失败。
`
Usafe
CAS算法在java中的实现usafe类。
public final native boolean compareAndSwapObject(Object paramObject1, long paramLong, Object paramObject2, Object paramObject3);
public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2);
public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3);
缺点
ABA问题。可以通过增加版本号解决。
模拟CAS
/**
* 模拟CAS
* @author xiaobin
* @date 2018/3/3
*/
public class TestCompareAndSwap {
public static void main(String[] args) {
final CompareAndSwap cas = new CompareAndSwap();
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));
System.out.println(b);
}
}).start();
}
}
}
class CompareAndSwap {
private int value ;
//获取内存值
public synchronized int get() {
return value;
}
//比较
public synchronized int compareAndSwap(int expecteValue, int newValue) {
int oldValue = value;
if (oldValue == expecteValue) {
this.value = newValue;
}
return oldValue;
}
//设置
public synchronized boolean compareAndSet(int expecteValue,int newValue) {
return expecteValue == compareAndSwap(expecteValue, newValue);
}
}