Java并发之AtomicInteger

AtomicInteger

AtomicInteger 是一个支持原子操作的 Integer 类,
保证对AtomicInteger类型变量的增加和减少操作是原子性

  • 继承自Number,实现Serializable接口

源码:

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;
  • value是用来存储整数的时间变量,使用volatile关键字
  • valueOffset是用来记录value本身在内存的编译地址的

  • unsafe是java提供的获得对对象内存地址访问的类
    Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。

  • static 代码块获取value字段的偏移量,这个偏移量类似于C语言中的指针值

自增返回新值incrementAndGet

    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

自增返回旧值getAndIncrement

public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

还有getAndDecrement、decrementAndGet

自增操作调用Unsafe类的getAndAddInt函数

public final int getAndAddInt(Object var1, long var2, int var4) {
      int var5;
      do {
         var5 = this.getIntVolatile(var1, var2);
      } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

      return var5;
   }

参考此处文章
http://ifeve.com/enhanced-cas-in-jdk8/

Unsafe是经过特殊处理的,不能理解成常规的java代码,区别在于:
在调用getAndAddInt的时候,如果系统底层支持fetch-and-add,那么它执行的就是native方法,使用的是fetch-and-add;
如果不支持,就按照上面的所看到的getAndAddInt方法体那样,以java代码的方式去执行,使用的是compare-and-swap;

CAS 比较并交换

  • CAS操作经常被用来实现无锁数据结构
  • 将内存值与预期值进行比较,如果相等才将新值替换到内存中,并返回true
  • 如果不相等,则直接返回false表示操作失败。

compareAndSwapInt()方法的声明如下,是一个native方法

 public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

该方法调用C++层JVM的源码。


CAS操作的ABA问题

CAS操作只有内存值与预期值相等才会更新内存中的值
CAS操作可能会出现这种现象:原来内存值为A,线程1和线程2都获取该值,
然后线程1使用CAS将内存值修改为B,然后又使用CAS将内存值修改回A;这时线程2使用CAS对内存值进行修改时发现内存值仍然是A,然后线程2修改成功。这种现象是“ABA问题”,也称“调包问题”。

链式数据结构可能会无故删除节点
Java中被无故删除的节点会被垃圾回收机制回收
但在C/C++中这就造成内存泄漏

猜你喜欢

转载自blog.csdn.net/moni_mm/article/details/80082301
今日推荐