AtomicInteger源码分析

CAS

CAS(Compare-And-Swap,比较并交换)操作是CPU中术语,它保证了操作的原子性。CAS指令需要三个操作数,分别是:

V:内存位置(也就是本次操作变量的内存地址);

A:旧的预期值;

B: 操作完成后的新值。

CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行更新,无论是否更新,都会返回V的旧值,整个CAS操作是一个原子操作。在JDK1.5之后,Java程序中才可以使用CAS操作,该操作由sun.misc.Unsafe类里的compareAndSwapXXX()方法包装提供,虚拟机在内部对这些方法做了特殊处理。在JDK1.5中提供了原子变量,如AtomicInteger,AtomicLong等,由并发大师Doug Lea操刀,提供了在单个变量上面不需要锁的线程安全性。现在就让我们走进AtomicInteger的世界中,探究它是如何实现的,并领略大师的风采。

AtomicInteger中原子操作的实现

通过这一小部分的分析,我们就弄明白了AtomicInteger中原子操作的实现,首先看看AtomicInteger中有哪些状态

[java]  view plain  copy
  1. public class AtomicInteger extends Number implements java.io.Serializable {  
  2.     private static final long serialVersionUID = 6214790243416807050L;  
  3.   
  4.     //使用Unsafe.compareAndSwapInt来执行修改操作,CAS是通过Unsafe.compareAndSwapXXX()方法实现的  
  5.     private static final Unsafe unsafe = Unsafe.getUnsafe();  
  6.     //value在内存中的地址偏移量  
  7.     private static final long valueOffset;  
  8.   
  9.     static {  
  10.       try {  
  11.         //获得value的内存地址偏移量  
  12.         valueOffset = unsafe.objectFieldOffset  
  13.             (AtomicInteger.class.getDeclaredField("value"));  
  14.       } catch (Exception ex) { throw new Error(ex); }  
  15.     }  
  16.     //当前对象代表的值,注意是volatile  
  17.     private volatile int value;  
在这一段代码中,我们需要注意三个方面,也就是AtomicInteger的三个字段:

(1)unsafe字段,AtomicInteger包含了一个Unsafe类的实例,unsafe就是用来实现CAS的;

(2)value字段,表示当前对象代码的基本类型的值,AtomicInteger是int型的线程安全包装类,value就代码了AtomicInteger的值。注意,这个字段是volatile的。

(3)valueOfset,通过字面意思就可以看出来valueOfset是value在内存中的偏移量,也就是在内存中的地址,通过Unsafe.objectFieldOffset(Field f)获取。前面在讲CAS时,我们提到需要操作内存的位置,valueOfset就是这个位置。

AtomicInteger中的CAS

public final boolean compareAndSet(int expect,int update)就是CAS的具体实现,其他所有的原子操作都是依赖于此方法,前面已经提到了,Java中的CAS是通过Unsafe类实现的,这个方法就是通过调用Unsafe.compareAndSwapInt(this,valueOfset,expect,udate)方法来实现的,其中valueOffset就是要操作的内存地址,expect是旧值,update是新值,当且仅当valueOffset内存中的值等于expect时,才用update更新旧值。其代码如下:

[java]  view plain  copy
  1. /** 
  2.      * 原子操作 
  3.      * CAS:Compare-and-Swap 
  4.      * 如果当前值==expect,则设置新值 
  5.      */  
  6.     public final boolean compareAndSet(int expect, int update) {  
  7.         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  8.     }  
AtomicInteger提供了好几个原子操作变量的方法:

int addAndGet(int delta)
将当前值与给定的值相加,并返回新值
boolean compareAndSet(int expect, int update)
当且仅当value==expect,value=update
int decrementAndGet()
自减1,并返回新值
   
int getAndAdd(int delta)
将当前值与给定值相加,并返回相加之前的值(旧值)
int getAndDecrement()
自减1,并返回旧值
int getAndIncrement()
自增1,并返回旧值
int getAndSet(int newValue)
将当前值与给定值相加,并返回旧值
int incrementAndGet()
自增1,并返回新值

可以看到,每一种操作(自增,自减,加给定值)都提供了对称的操作,其中getAndXXX()方法是返回旧值,XXXAndGet()返回的是新值。这些操作的实现方式都是相同的,我们以getAndIncrement()为例,来讲解它是如何实现原子操作的。首先看getAndIncrement()的源码:

[java]  view plain  copy
  1. /** 
  2.      * 原子操作,实现自增操作,通过CAS实现,返回自增之前的值 
  3.      * 实现原理是这样的: 
  4.      * 1.首先获得当前值,保存到current中,next=current + 1 
  5.      * 2.如果CAS成功,则返回current 
  6.      *   如果CAS不成功,这说明刚刚有其他的线程修改了当前值,current已经失效了,next也已经失效了 
  7.      *   只能重新获取当值,并继续CAS,直到成功为止 
  8.      */  
  9.     public final int getAndIncrement() {  
  10.         for (;;) {  
  11.             int current = get();  
  12.             int next = current + 1;  
  13.             if (compareAndSet(current, next))  
  14.                 return current;  
  15.         }  
  16.     }  
在上面的注释中已经说的比较明白了,但我还是愿意再啰嗦两句:

(1)首先获得当前值,保存到current中,并把current的下一个值保存到next中,next=current+1

(2)调用compareAndSet(current,next)尝试自增,如果自增成功,则返回current;如果自增失败,则说明已经有其他线程修改value的值,current中的值和next中的值已经失效了,要重新获取当前值,重复刚才的CAS操作,直到成功位置。

可以看到,通过第(2)步的操作,确实实现了多线程下的安全,即使在自增的时候有其他线程修改了当前值,自增操作也不会覆盖已经修改的值,而是在当前最新值的基础上实现自增。演示一下不使用CAS的错误情况和这种实现方式的正确性

a.错误的自增,假设当前value=8,同时有两个线程t1,t2对value执行自增操作,执行顺序如下:


执行完成后,t2的值把t1的值给覆盖了,执行完成后,现在value=9,正确的结果应该是10。在下图中,通过CAS以同样的顺序执行,获得的结果就是正确的:


上面的分析基本上就概括了AtomicInteger实现的全部了。但是CAS并不是没有缺点,概括起来说,CAS就三个缺点:

(1)ABA问题,如果V的初始值是A,在准备赋值的时候检查到它仍然是A,那么能说它没有改变过吗?也许V经历了这样一个过程:它先变成了B,又变成了A,使用CAS检查时以为它没变,其实却变里;

(2)循环时间长,开销大,通过自旋CAS一直在消耗CPU

(3)只能保证一个共享变量的原子操作,当对多个共享变量操作时就无法保证原子性了。

AtomicInteger源码分析

[java]  view plain  copy
  1. package com.java.source;  
  2.   
  3. import sun.misc.Unsafe;  
  4.   
  5. public class AtomicInteger extends Number implements java.io.Serializable {  
  6.     private static final long serialVersionUID = 6214790243416807050L;  
  7.   
  8.     //使用Unsafe.compareAndSwapInt来执行修改操作,CAS是通过Unsafe.compareAndSwapXXX()方法实现的  
  9.     private static final Unsafe unsafe = Unsafe.getUnsafe();  
  10.     //value在内存中的地址偏移量  
  11.     private static final long valueOffset;  
  12.   
  13.     static {  
  14.       try {  
  15.         //获得value的内存地址偏移量  
  16.         valueOffset = unsafe.objectFieldOffset  
  17.             (AtomicInteger.class.getDeclaredField("value"));  
  18.       } catch (Exception ex) { throw new Error(ex); }  
  19.     }  
  20.     //当前对象代表的值,注意是volatile  
  21.     private volatile int value;  
  22.   
  23.     /*使用给定的值创建对象,也就是把给定的值包装起来*/  
  24.     public AtomicInteger(int initialValue) {  
  25.         value = initialValue;  
  26.     }  
  27.   
  28.     /*默认初始化为0*/  
  29.     public AtomicInteger() {  
  30.     }  
  31.       
  32.     /*getter/setter*/  
  33.     public final int get() {  
  34.         return value;  
  35.     }  
  36.     public final void set(int newValue) {  
  37.         value = newValue;  
  38.     }  
  39.   
  40.     /*最后设置指定的值*/  
  41.     public final void lazySet(int newValue) {  
  42.         unsafe.putOrderedInt(this, valueOffset, newValue);  
  43.     }  
  44.   
  45.    /*原子操作:设定新值,返回旧值,通过CAS完成*/  
  46.     public final int getAndSet(int newValue) {  
  47.         for (;;) {  
  48.             int current = get();  
  49.             if (compareAndSet(current, newValue))  
  50.                 return current;  
  51.         }  
  52.     }  
  53.   
  54.     /** 
  55.      * 原子操作 
  56.      * CAS:Compare-and-Swap 
  57.      * 如果当前值==expect,则设置新值 
  58.      */  
  59.     public final boolean compareAndSet(int expect, int update) {  
  60.         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  61.     }  
  62.   
  63.     /** 
  64.      * 原子操作,功能与compareAndSet一样 
  65.      * 有可能意外失败,且不保证排序,但是调用的代码是完全一样的,JVM又在内部做了手脚? 
  66.      * 在极少情况下用来替代compareAndSet 
  67.      */  
  68.     public final boolean weakCompareAndSet(int expect, int update) {  
  69.         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  70.     }  
  71.   
  72.     /** 
  73.      * 原子操作,实现自增操作,通过CAS实现,返回自增之前的值 
  74.      * 实现原理是这样的: 
  75.      * 1.首先获得当前值,保存到current中,next=current + 1 
  76.      * 2.如果CAS成功,则返回current 
  77.      *   如果CAS不成功,这说明刚刚有其他的线程修改了当前值,current已经失效了,next也已经失效了 
  78.      *   只能重新获取当值,并继续CAS,直到成功为止 
  79.      */  
  80.     public final int getAndIncrement() {  
  81.         for (;;) {  
  82.             int current = get();  
  83.             int next = current + 1;  
  84.             if (compareAndSet(current, next))  
  85.                 return current;  
  86.         }  
  87.     }  
  88.   
  89.     /** 
  90.      * 原子操作,实现自减,通过CAS实现,返回当前值 
  91.      * 实现方法同getAndIncrement()相同 
  92.      */  
  93.     public final int getAndDecrement() {  
  94.         for (;;) {  
  95.             int current = get();  
  96.             int next = current - 1;  
  97.             if (compareAndSet(current, next))  
  98.                 return current;  
  99.         }  
  100.     }  
  101.   
  102.     /** 
  103.      * 原子操作,将当前值增加delta,并返回当前值 
  104.      * 实现原理同getAndIncrement()相同,只不过一个是增1,一个是增delta 
  105.      */  
  106.     public final int getAndAdd(int delta) {  
  107.         for (;;) {  
  108.             int current = get();  
  109.             int next = current + delta;  
  110.             if (compareAndSet(current, next))  
  111.                 return current;  
  112.         }  
  113.     }  
  114.   
  115.     /*原子操作,自增一,并返回增加后的值*/  
  116.     public final int incrementAndGet() {  
  117.         for (;;) {  
  118.             int current = get();  
  119.             int next = current + 1;  
  120.             if (compareAndSet(current, next))  
  121.                 return next;  
  122.         }  
  123.     }  
  124.   
  125.    /*原子操作,自减,并返回减小后的值*/  
  126.     public final int decrementAndGet() {  
  127.         for (;;) {  
  128.             int current = get();  
  129.             int next = current - 1;  
  130.             if (compareAndSet(current, next))  
  131.                 return next;  
  132.         }  
  133.     }  
  134.   
  135.     /*原子操作,增加delta,并返回增加后的操作*/  
  136.     public final int addAndGet(int delta) {  
  137.         for (;;) {  
  138.             int current = get();  
  139.             int next = current + delta;  
  140.             if (compareAndSet(current, next))  
  141.                 return next;  
  142.         }  
  143.     }  
  144.   
  145.    /** 
  146.     * 一些常规方法 
  147.     */  
  148.     public String toString() {  
  149.         return Integer.toString(get());AtomicLong  
  150.     }  
  151.   
  152.       
  153.     public int intValue() {  
  154.         return get();  
  155.     }  
  156.   
  157.     public long longValue() {  
  158.         return (long)get();  
  159.     }  
  160.   
  161.     public float floatValue() {  
  162.         return (float)get();  
  163.     }  
  164.   
  165.     public double doubleValue() {  
  166.         return (double)get();  
  167.     }  
  168.   
  169. }  

转载出处:点击打开链接


举个例子:(原创)

public class bingfa {
    public static void main(String[] args) {
        RunTest task = new RunTest();
        new Thread(task).start();
        new Thread(task).start();
        try {
            Thread.sleep(3000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(task.count);
    }
}
class RunTest implements Runnable{

    //public int count;   //输出结果不为2000
    AtomicInteger count = new AtomicInteger(0);  //输出结果为2000
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            //count++;
            count.addAndGet(1);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值