AtomicInteger介绍

内容引用:
原子变量(AtomicLong, AtomicInteger, AtomicReference)
Java线程(十):CAS
无锁队列的实现

概述

一个提供原子操作的Integer的类。在Java语言中,++i和i++操作是“读-改-写”复合操作(在一个操作序列中,后一个操作依赖前一次操作的结果),在多线程并发处理的时候会出现问题,因为可能一个线程修改了变量,而另一个线程没有察觉到这样变化,所以并不是线程安全的。在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则将该操作变为原子操作。

CAS (Compare And Swap)

  • 对内存中的共享数据进行操作的一种特殊指令,这个指令会对内存中的共享数据做原子的读写操作。
  • 操作过程:首先CPU会将内存中将要被更改的数据与期望的值作比较,当两个值相等时将内存中的数值更换为新值,否则不操作,最后返回旧值。即CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则返回V。
  • 这是一种乐观锁的思路,它相信在它修改之前,没有其他线程修改过;而Synchronized是一种悲观锁,它认为在它修改之前,一定会有其它线程去修改它,悲观锁效率很低。
  • 实现非阻塞式的原子性操作,但是会产生ABA问题,即:

    1. 进程P1在共享变量中读到值为A
    2. P1被抢占了,进程P2执行
    3. P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占。
    4. 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。

你可能感兴趣的:(java并发)