java中的13个原子类操作
13个原子类操作主要分为四大类:原子更新基本类型,原子更新数组,原子更新引用,原子更新属性(字段)
atomic 的类基本都是unsafe类的包装类
原子更新基本类型包括:
atomicBoolean
atomicIneger
atomicLong
这里注意lazyset方法,Doug Lea大神已经在oracle官网解释了,原文如下
"As probably the last little JSR166 follow-up for Mustang,
we added a "lazySet" method to the Atomic classes
(AtomicInteger, AtomicReference, etc). This is a niche
method that is sometimes useful when fine-tuning code using
non-blocking data structures. The semantics are
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 be visible to other threads) until
some other volatile write or synchronizing action occurs).
The main use case is for nulling out fields of nodes in
non-blocking data structures solely for the sake of avoiding
long-term garbage retention; it applies when it is harmless
if other threads see non-null values for a while, but you‘d
like to ensure that structures are eventually GCable. In such
cases, you can get better performance by avoiding
the costs of the null volatile-write. There are a few
other use cases along these lines for non-reference-based
atomics as well, so the method is supported across all of the
AtomicX classes.
For people who like to think of these operations in terms of
machine-level barriers on common multiprocessors, lazySet
provides a preceeding store-store barrier (which is either
a no-op or very cheap on current platforms), but no
store-load barrier (which is usually the expensive part
of a volatile-write)."
###@###.### 2005-05-24 17:04:
外链地址如下
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329
大概意思就是使用该方法取掉了 storeload屏障,只保留storestore屏障,
在屏障中storeload屏障是最耗资源的,因此使用该方法对提高效率有一定好处,虽然不能保证写完之后立即被其他线程可见,但是能保证写的顺序,同时该方法职能处理有volatile的对象,使用该方法要注意一定的使用场景。
典型的atomicInteger的getAndIncrement方法如下:
public final int getAndIncrement(){
int current=get();
while(true){
if(compareandset(current,current+1)){
return current;
}
}
//compareandset 使用unsafe类实现
public final boolean compareandset(int expect ,int update){
unsafe.compareandswapint(this,expect,valueoffset,update);
}
}
根据unsafe类提供的swap方法,在使用时需要将包装类转换成基本类型再使用unsafe类中的compareandswap方法
在atomic包中,并没有提供 char float double 类型的swap方法,可以采用转换成object包装类,或者转换成long类型进行处理
更新原子数组类
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
//使用代码实例
public class AtomicIntegerArrayTest{
static int[] value=new int[2]{1,2};
static AtomicIntegerArray ai = new AtomicInteger(value);
public static void main(String[] args){
ai.getandset(0,3);//设置第一位为3
System.out.println(ai.get(0));// 结果3
System.out.println(value[0]);//结果1
}
}
根据伪代码结果发现结果不一致,主要原因:ai通过构造方法复制了一份value所以对ai修改时,不会影响value的值
原子更新引用类型
原子更新基本类型的AtomicInteger,只能更新一个变量,如果更新多个变量就需要使用原子更新引用类
AtomicReference 原子更新引用类型
AtomicReferenceFieldUpdater 原子更新引用对象里的字段
AtomicMarkableReference 原子更新带有标记位的引用类型
原子更新引用类型的字段
如果需要原子更新引用对象的字段时,就需要使用原子更新字段类,atomic包包含了以下工具类
AtomicIntegerFieldUpdater
AtomicLongFieldUpdate
AtomicStampedReference:原子更新带有版本号的引用类型,可用于原子更新的版本号和引用数据,可以有效解决原子更新的aba问题。原子更新主要分为两步:因为原始更新字段类都是抽象类,必须使用静态方法 newUpdater()创建一个更新器,并且需要设置更新器的类型和属性,第二步,更新类的字段必须使用 public volatitle字段进行修饰
调用伪代码如下:
public class FieldUpdater{
AtomicIntegerFieldUpdater a = AtomicIntegerFieldUpdater.newUpdater(User.class,age);
static class User{
private String name;
private volatitle int age;
}
public static void main(String[] args){
User coman = new User("coman",10);
System.out.println(a.getAndIncrement(coman));
System.out.println(a.get(coman));
}
}