内容引用: 原子变量(AtomicLong, AtomicInteger, AtomicReference) Java线程(十):CAS 无锁队列的实现
一个提供原子操作的Integer的类。在Java语言中,++i和i++操作是“读-改-写”复合操作(在一个操作序列中,后一个操作依赖前一次操作的结果),在多线程并发处理的时候会出现问题,因为可能一个线程修改了变量,而另一个线程没有察觉到这样变化,所以并不是线程安全的。在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则将该操作变为原子操作。
实现非阻塞式的原子性操作,但是会产生ABA问题,即:
进程P1在共享变量中读到值为AP1被抢占了,进程P2执行P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占。P1回来看到共享变量里的值没有被改变,于是继续执行。 虽然P1以为变量值没有改变,继续执行了,但是这个会引发一些潜在的问题。AtomicInteger就是利用CAS实现原子性操作的。java.util.concurrent.atomic : Java并发包,是对Java部分数据类型的原子封装,在原有数据类型的基础上,提供了原子性的操作方法,保证了线程安全。
//成员变量 (volatile,保证其内存可见性) private volatile int value; //部分成员方法 (全是final的) /* Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that the actual value was not equal to the expected value.*/ // CAS实现 // 单线程下, compareAndSet返回永远为true; // 多线程下, 在将expect与最新的value(volatile的,可以实时看到最新值) 进行compare时, value可能被其他线程set了新值,而造成compare不相等,返回false。 public final boolean compareAndSet(int expect, int update) { // 比较并设置,这里利用Unsafe类的JNI方法实现,使用CAS指令,可以保证读-改-写是一个原子操作。 return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } // 获取当前的值,并自增 public final int getAndIncrement() { // 除非执行return语句否则一直循环程序体,重试到成功为止,保证能够线程安全地(原子的)改变当前值。 for (;;) { // 这样优于while(true) int current = get(); int next = current + 1; if (compareAndSet(current, next)) // 进行CAS操作 return current; } } // 获取当前的值,并加上预期的值 public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } }Volatile + CAS 具体见上面的注释。
原子变量只能保证对一个变量的操作是原子的,如果有多个原子变量之间存在依赖的复合操作,也不可能是安全的。另外一种情况是要将更多的复合操作作为一个原子操作,则需要使用synchronized将要作为原子操作的语句包围起来。因为涉及到可变的共享变量(类实例成员变量)才会涉及到同步,否则不必使用synchronized。