volatile
volatile可以实现变量的可见性,即取值操作是线程安全的,但是变量本身在多线程的情况下仍然不是线程安全的,例如
volatile int i;
i++;
CAS
CAS英文解释是比较和交换,是cpu底层的源语,是解决共享变量原子性实现方案,它定义了三个变量,内存地址值对应V,期待值E和要修改的值U.在Java中通过调用UnSafe的compareAndSet类似方式调用,底层是c,反编译后操作系统指令是cmpxchg指令。
CAS操作经常被用来实现无锁数据结构。在
java.util.concurrent
包中就有很多这样的数据结构:ConcurrentLinkedQueue
、ConcurrentLinedDeque
、ConcurrentHashMap
、ConcurrentSkipListMap
、ConcurrentSkipListSet
AtomicInteger
AtomicInteger类在java.util.concurrent.atomic 包下。可以用来实现线程安全的int变量。下面是这个类的代码片段,可以看到++和--操作都调用了unsafe类的方法,通过CAS实现了一定程度的线程安全
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
public AtomicInteger(int initialValue) {
value = initialValue;
}
public AtomicInteger() {
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
//等效于线程安全的i++操作
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
//等效于线程安全的i--操作
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
}
CAS存在ABA问题
cas是线程安全的吗?不是绝对线程安全的。
CAS操作只有内存值与预期值相等才会更新内存中的值,所有CAS操作可能会出现这种现象:原来内存值为A,线程1和线程2都对i值操作,i初始值为1,线程1使用CAS将i值修改为5,然后又使用CAS将内存值修改回1;这时线程2使用CAS对i值进行修改时发现内存值仍然是1,然后线程2修改成功。这种现象是“ABA问题”。