AtomicInteger源码解析
AtomicInteger类介绍
AtomicInteger是在JDK的java.util.concurrent.atomic包中提供的,线程安全的Integer操作类。之所以说它是线程安全的,是相对于int类型的数据来说的。
比如下面这个例子:
1 | public class UseIntUnsafe implements Runnable { |
上述代码做的事情:
- 声明一个静态的int值value
- 实现Runnable接口,并实现其run方法
- 在run方法中对value自增1000次
- 开启5个线程,每个线程对value自增1000次
- 观察结果。
运行上述代码,可以发现每次跑完的结果都不一样:
这是因为int类型在自增的时候(i++或者++i),不是一个原子操作完成的。它大略可以分为三步
- 从原来的地址中取出值
- 对值加1
- 放回原来的地址
这三步中,任何一步在执行的时候,线程被切换走,都会导致最后结果的不一致。
因此,JDK就提供了一个采用CAS思想实现的原子类AtomicInteger。
类图
AtomicInteger继承了抽象类Number,并实现了其longValue,doubleValue等方法。
主要属性
1 | // setup to use Unsafe.compareAndSwapInt for updates |
unsafe:是sun封装出来,主要实现CAS算法的实现类。Atomic*的类都是借助这个Unsafe类实现的
valueOffset:当前值value在整个类对象内存地址中的偏移值。这个值在一个静态的代码块中完成初始化
1 | static { |
value:当前值
主要方法
AtomicInteger()
1 | /** |
无参构造函数,value取默认值0
AtomicInteger(int)
1 | /** |
有参构造函数,将value的值初始化为指定的initialValue
get()
1 | /** |
获取当前值
set(int)
1 | /** |
因为value是volatile修饰的,可以直接设值
lazySet(int)
1 | /** |
lazySet方法是由依赖于硬件的系统指令(如x86的xchg)实现的。使用lazySet的话,其他线程在之后的一小段时间里还是可以读到旧的值。lazySet方法相比于set
方法可能性能好一点。
getAndSet(int)
1 | /** |
设置新值,并返回当前值
compareAndSet(int, int)
1 | /** |
当当前值等于expect的时候,将其设置为新值update。设置成功返回true,否则flase
weakCompareAndSet(int, int)
1 | /** |
这个方法的本意是,调用weakCompareAndSet方法时不能保证指令重排的发生,因此,这个方法有时候会毫无理由地失败。
但是从实现上来看,这个方法还是和compareAndSet一模一样的。不过建议在使用的时候,谨慎对待,保不定什么时候,方法实现就修改了。
getAndIncrement
1 | /** |
将当前值自增1,并返回自增前的值
getAndDecrement()
1 | /** |
将当前值自减1,并返回自增前的值
getAndAdd(int)
1 | /** |
将value加上指定的值,并返回未加之前的值
incrementAndGet()
1 | /** |
将当前值加1,并返回最新值
decrementAndGet()
1 | /** |
将当前值减1,并返回最新值
addAndGet(int)
1 | /** |
将当前值加上指定的delta,并返回最新的值
getAndUpdate(IntUnaryOperator)
1 | /** |
用传入的单元函数对象计算并更新当前值,并返回更新之前的当前值
要求单元函数对象调用支持幂等,因为存在设值失败的场景。
updateAndGet(IntUnaryOperator)
1 | /** |
用传入的函数对象计算并更新当前值,并返回更新之后的当前值
要求单元函数对象调用支持幂等,因为存在设值失败的场景。
getAndAccumulate(int , IntBinaryOperator)
1 | /** |
value由当前值和传入的x和双元运算函数得到,并更新,返回更新前的value
要求双元运算函数具有幂等性,因为存在设值失败的场景
accumulateAndGet(int, IntBinaryOperator)
1 | /** |
value由当前值和传入的x和双元运算函数得到,并更新,返回更新后的value
要求双元运算函数具有幂等性,因为存在设值失败的场景
toString()
1 | /** |
返回当前value值的字符串形式
intValue()
1 | /** |
返回当前value值
longValue()
1 | /** |
将当前值强转为long型,返回
floatValue()
1 | /** |
将当前值强转为float返回
doubleValue()
1 | /** |
将当前值强转为double返回
使用
了解了AtomicInteger的主要方法之后,我们再试着使用AtomicInteger改写上面的线程不安全的代码。
1 | public class UseAtomicInteger implements Runnable { |