首页 > 代码库 > java.util.concurrent.AtomicInteger

java.util.concurrent.AtomicInteger

AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

来看AtomicInteger提供的接口。

//获取当前的值

public final int get()

//取当前的值,并设置新的值

 public final int getAndSet(int newValue)

//获取当前的值,并自增

 public final int getAndIncrement()

//获取当前的值,并自减

public final int getAndDecrement()

//获取当前的值,并加上预期的值

public final int getAndAdd(int delta)

... ...

为什么说atomicInteger是线程安全的呢?

在AtomicInteger的源码中相关的代码如下:

Java代码  收藏代码

  1. // setup to use Unsafe.compareAndSwapInt for updates  

  2. private static final Unsafe unsafe = Unsafe.getUnsafe();  

  上面这行代码是获取Unsafe实例的。一般情况下,我们是拿不到该类的实例的,当然jdk库里面是可以随意使用的。

 

 

Java代码  收藏代码

  1. static {  

  2.      try {  

  3.        valueOffset = unsafe.objectFieldOffset  

  4.            (AtomicInteger.class.getDeclaredField("value"));  

  5.      } catch (Exception ex) { throw new Error(ex); }  

  6.    }  

 

  上面这几行代码,是用来获取AtomicInteger实例中的value属性在内存中的位置。这里使用了Unsafe的objectFieldOffset方法。这个方法是一个本地方法, 该方法用来获取一个给定的静态属性的位置。

 

Java代码  收藏代码

  1. public native long objectFieldOffset(Field f);  

 

这里有个疑问,为什么需要获取属性在内存中的位置?通过查看AtomicInteger源码发现,在这样几个地方使用到了这个valueOffset值:

 

Java代码  收藏代码

  1. public final void lazySet(int newValue) {  

  2.         unsafe.putOrderedInt(this, valueOffset, newValue);  

  3.     }  

 

Java代码  收藏代码

  1. public final boolean compareAndSet(int expect, int update) {  

  2.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  

  3.     }  

 

 

Java代码  收藏代码

  1. public final boolean weakCompareAndSet(int expect, int update) {  

  2.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  

  3.     }  

 

  查找资料后,发现lazySet方法大多用在并发的数据结构中,用于低级别的优化。compareAndSet这个方法多见于并发控制中,简称CAS(Compare And Swap),意思是如果valueOffset位置包含的值与expect值相同,则更新valueOffset位置的值为update,并返回true,否则不更新,返回false。

这里可以举个例子来说明compareAndSet的作用,如支持并发的计数器,在进行计数的时候,首先读取当前的值,假设值为a,对当前值 + 1得到b,但是+1操作完以后,并不能直接修改原值为b,因为在进行+1操作的过程中,可能会有其它线程已经对原值进行了修改,所以在更新之前需要判断原值是不是等于a,如果不等于a,说明有其它线程修改了,需要重新读取原值进行操作,如果等于a,说明在+1的操作过程中,没有其它线程来修改值,我们就可以放心的更新原值了。