AtomicInteger 理论与实践

publicclass AtomicInteger

extends Number

implements Serializable

 

可以用原子方式更新的 int 值。有关原子变量属性的描述,请参阅 java.util.concurrent.atomic 包规范。AtomicInteger 可用在应用程序中(如以原子方式增加的计数器),并且不能用于替换 Integer。但是,此类确实扩展了 Number,允许那些处理基于数字类的工具和实用工具进行统一访问。

 

概述:

JavaAPI的说明中:AtomicInteger可以原子的更新int值。从应用程序的角度来看,我们可以使用AtomicInteger来构建以原子方式增加的计数器。

源码分析:

1 使用CAS进行原子更新操作。

Java并发包中大量使用了CAS操作。CAS 操作包含三个操作数 ——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。

 // 定义unsafe 成员变量

private static finalUnsafe unsafe = Unsafe.getUnsafe();

 

// 取得value字段的偏移量

static {

  try {

    valueOffset = unsafe.objectFieldOffset

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

  } catch (Exception ex) { throw newError(ex); }

}

// 原子操作:比较并更新

public final booleancompareAndSet(int expect, int update) {

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

}

// 原子操作:比较并更新

public final booleanweakCompareAndSet(int expect, int update) {

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

}

 

Java中具体的CAS操作类是sun.misc.UnsafeUnsafe类提供了硬件级别的原子操作,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。在OpenJDK公开的Unsafe源代码中,可以看到Unsafe类的方法都是通过native关键字从而将实现委托给操作系统了。

public native longobjectFieldOffset(Field f);

 

public final native booleancompareAndSwapInt(Object o, long offset,

                                                 int expected,

                                                 int x);

 

2 使用volatile关键字修饰int成员变量value

privatevolatile int value;

volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的值是相同的,更简单一点理解就是volatile修饰的变量值发生变化时对于另外的线程是可见的。

关于volatile修饰符的相信信息可参考Java理论与实践:正确使用volatile变量 一文。

注意点

对于AtomicInteger提供的公开API,大部分都一目了然,不用多说,有两点值得注意。

首先是比较并交换,公开的API中提供了两种方案:compareAndSetweakCompareAndSet。尽管规范中说:weakCompareAndSet可能会在意外的情况下失败,并对指令重排序不提供保证,但是从实现的角度来看,这两个方法都是调用unsafe.compareAndSwapInt(this, valueOffset, expect, update)来实现的,因此实现并没有遵守规范。也许将来会重新实现这个方法,只是目前还缺乏合适的解决方案。

其次就是1.6新增的lazySet方法。

 

Unsafe.putOrderedObject guarante that writes will notbe re-orderd by instruction reordering. Under the covers it uses the fasterstore-store barrier, rather than the the slower store-load barrier, which isused when doing a volatile write.

write may be reordered with subsequent operations (orequivalently, might not be visible to other threads) until some other volatilewrite or synchronizing action occurs)

 

也就是说能够保证写写不会被重排序,但是不保证写会对其它线程可见,而volatile既保证写写不会被重排序,也保证写后对其它线程立即可见。可见Unsafe.putOrderedObject会比直接的volatile变量赋值速度会一点,这篇文章则指出Unsafe.putOrderedObject会比volatile写快3倍。

 

源文档 <http://onlychoice.github.io/blog/2013/09/17/java-concurrent-source-code-reading-3/>

 

 

As probably the last little JSR166 follow-up forMustang, we added a "lazySet" method to the Atomic classes(AtomicInteger, AtomicReference, etc). This is a niche method that is sometimesuseful when fine-tuning code using non-blocking data structures. The semanticsare that the write is guaranteed not to be re-ordered with any previous write,but may be reordered with subsequent operations (or equivalently, might not bevisible to other threads) until some other volatile write or synchronizingaction occurs).

The main use case is for nulling out fields ofnodes in non-blocking data structures solely for the sake of avoiding long-termgarbage retention; it applies when it is harmless if other threads see non-nullvalues for a while, but you'd like to ensure that structures are eventuallyGCable. In such cases, you can get better performance by avoiding the costs ofthe null volatile-write. There are a few other use cases along these lines fornon-reference-based atomics as well, so the method is supported across all ofthe AtomicX classes.

For people who like to think of these operationsin terms of machine-level barriers on common multiprocessors, lazySet providesa preceeding store-store barrier (which is either a no-op or very cheap oncurrent platforms), but no store-load barrier (which is usually the expensivepart of a volatile-write).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值