这里看一下原子数组操作和一些其他的原子操作。

AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API类似,选择代表性的AtomicIntegerArray来描述这些问题。

int get(int i) //获得当前位置的值
void set(int i, int newValue) //设置给定位置的值
void lazySet(int i, int newValue)
int getAndSet(int i, int newValue)
boolean compareAndSet(int i, int expect, int update)
boolean weakCompareAndSet(int i, int expect, int update)
int getAndIncrement(int i)
int getAndDecrement(int i)
int getAndAdd(int i, int delta)
int incrementAndGet(int i)
int decremnetAndGet(int i)
int addAndGet(int i, int delta)

这些API和AtomicInteger是类似的,区别是这里是数组操作,所以多个索引参数。

由于这个是数组操作,就存在数组越界的问题(IndexOutBoundsException异常),所以在get/set方法前都会检查int index是否合法。先来看看该类的主要成员.

    private static final Unsafe unsafe = Unsafe.getUnsafe();private static final int base = unsafe.arrayBaseOffset(int[].class);private static final int shift;private final int[] array;

Unsafe.getUndafe()就不说了,CAS操作少不了他;

base :通过Unsafe获得数组的基址;

shift : 数组每个元素在内存的偏移量;

array : 底层实际操作数组;

  static {int scale = unsafe.arrayIndexScale(int[].class);          //数组元素的大小,必须为2^x大小if ((scale & (scale - 1)) != 0)throw new Error("data type scale not a power of two");shift = 31 - Integer.numberOfLeadingZeros(scale);   //数组元素的bit偏移量}

数组index检查:

   private long checkedByteOffset(int i) {if (i < 0 || i >= array.length)      //索引index越界。throw 异常throw new IndexOutOfBoundsException("index " + i);return byteOffset(i);}private static long byteOffset(int i) {     //取得指定index元素的内存位置(base + offset)return ((long) i << shift) + base;}

set/get时进行index检查:

 public final int get(int i) {return getRaw(checkedByteOffset(i));} public final void set(int i, int newValue) {unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);}

<********************************************************字段*********************************************************************>

AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdate<T,V>

上面三种是基于反射的原子更新字段的值。

相应的API也是比较简单,但是也是有一些约束的。

  1. 字段必须是volatile类型的!
  2. 字段的描述类型(修饰符public/protected/default/private)作用于调用者与操作对象的关系。即调用者能够直接操作对象字段,那么就可以反射进行原子操作证。private类型字段,调用者无法访问,更新该变量,protected类型变量成员,当操作对象为调用者class的实例或者子类时,可以访问,原子更新protected成员。
  3. 只能是实例变量,不能是类变量,也就是说不能加static关键字。
  4. 只能是可修改变量,不能使用final变量,因为final的语义就是不可修改。实际上final语义和volatile是由冲突的,这两关键字不能同时存在
  5. 对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型字段,不能修改其包装器类型(Integer/Long)。如果要修改包装器类型需要使用AtomicReferenceFieldUpdater。

   

      以AtomicIntegerFieldUpdater为例:

public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());}

AtomicIntegerFieldUpdater为一个抽象类,通过static newUpdater()方法获得其实现类实例,参数为操作对象Class对象,和其变量成员名:

public abstract class  AtomicIntegerFieldUpdater<T>private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T>

AtomicIntegerFieldUpdater的抽象方法定义如下:

    public abstract boolean compareAndSet(T obj, int expect, int update);public abstract boolean weakCompareAndSet(T obj, int expect, int update);public abstract void set(T obj, int newValue);public abstract void lazySet(T obj, int newValue);public abstract int get(T obj);

再来看看其实现类内部:

        private final long offset; //成员变量的内存偏移量private final Class<T> tclass; //操作对象的class对象private final Class cclass;  //调用者class对象

在进行成员更新访问时,都必须进行所谓的访问权限检查,上面几点以说明:

sun.reflect.misc.ReflectUtil.ensureMemberAccess( //成员变量访问权限的确定(排除private)
        caller, tclass, null, modifiers);
  sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); //包访问权限

 Class fieldt = field.getType();if (fieldt != int.class)throw new IllegalArgumentException("Must be integer type");     //变量成员的类型必须为intif (!Modifier.isVolatile(modifiers))                                //变量成员必须要关键字volatile修饰。throw new IllegalArgumentException("Must be volatile type");this.cclass = (Modifier.isProtected(modifiers) &&           //1.当成员为protected时,赋值  cclass = caller(赋值调用者class对象) 2:不为protected时,赋值 cclass = null.caller != tclass) ? caller : null;

 private void fullCheck(T obj) {if (!tclass.isInstance(obj))  //操作对象不为newUpdate()传入的class的实例或子类时,throw. throw new ClassCastException();if (cclass != null)  //上面以分析,当成员没有proteced修饰时, cclass 为null,所以不要进一步检查,直接放行,
                ensureProtectedAccess(obj);}

当变量为proteced修饰时:

 private void ensureProtectedAccess(T obj) {if (cclass.isInstance(obj)) {  //当要原子操作的对象obj为调用者class的实例或者子类时,放行,运行原子操作,否则Throw。return;}throw new RuntimeException(new IllegalAccessException("Class " +cclass.getName() +" can not access a protected member of class " +tclass.getName() +" using an instance of " +obj.getClass().getName()));}

AtomicMarkableReference类描述的一个<Object, Boolean>的pair,可以原子的修改object或者boolean的值,这种数据结构在一些缓存或者章台描述中比较有用。这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量。

private static class Pair<T> {final T reference;final boolean mark;private Pair(T reference, boolean mark) {this.reference = reference;this.mark = mark;}static <T> Pair<T> of(T reference, boolean mark) {return new Pair<T>(reference, mark);}}private volatile Pair<V> pair;

看看它的cas操作:

 public boolean compareAndSet(V       expectedReference,V       newReference,boolean expectedMark,boolean newMark) {Pair<V> current = pair;returnexpectedReference == current.reference &&  //在expectReference == current.Ref && expectMark == current.mark 并且新值pair中有任意一个或者两个都不等于目前值时,才更新expectedMark == current.mark &&((newReference == current.reference &&newMark == current.mark) ||casPair(current, Pair.of(newReference, newMark)));}

AtomicStampedReference类维护带有整数”标志“的对象引用,可以用原子方法对其进行更新。对比AtomicMarkableReference类的pair<Object, Boolean>,AtomicStampedReference维护的是一种类似于<Object, Integer>的数据结构,其实是对对象引用的一个并发计数。

 private static class Pair<T> {final T reference;final int stamp;private Pair(T reference, int stamp) {this.reference = reference;this.stamp = stamp;}static <T> Pair<T> of(T reference, int stamp) {return new Pair<T>(reference, stamp);}}private volatile Pair<V> pair;

  public boolean compareAndSet(V   expectedReference,V   newReference,int expectedStamp,int newStamp) {Pair<V> current = pair;returnexpectedReference == current.reference &&expectedStamp == current.stamp &&((newReference == current.reference &&newStamp == current.stamp) ||casPair(current, Pair.of(newReference, newStamp)));}

两种在解决CAS ”ABA“问题上很有用。

参考:http://www.blogjava.net/xylz/archive/2010/07/02/325079.html

转载于:https://www.cnblogs.com/onlysun/p/4619710.html

J.U.C atomic 数组,字段原子操作相关推荐

  1. php数据库根据相似度排序,php数组字段相似度排序

    摘要:今天有一个客户有这么一个需求,要求对某篇文章的相关内容的列表,在跟文章标题进行相似度排序,于是想了又想,写了一个小算法,可以根据关键字相似度对数组某个字段进行排序... 今天有一个客户有这么一个 ...

  2. TClientDataSet[22]: 数组字段与 ObjectView

    数组字段(ftArray) 与 ADT 字段类似(设计过程一样), 定义数组字段时只需定义一个元素来说明元素类型. 本例同时测试 ObjectView 为 True 和 False 时的不同效果. 下 ...

  3. Elasticsearch 搜索数组字段

    我的个人博客:逐步前行STEP 1.搜索 数组字段 tags 中同时存在元素 str_a.str_b {"query": {"bool": {"fil ...

  4. Laravel + MongoDB 数组字段相关查询

    我的个人博客:逐步前行STEP 1.$exist 查询 是否存在这个字段 //查询所有存在标签你字段的博客 App\Blog::where('tags','$exist',true)->get( ...

  5. Pgsql中数组字段当作查询条件和输出数组

    1.博客中关于 PostgreSql Array操作的操作符和函数 https://my.oschina.net/Kenyon/blog/133974 2.官方文档: https://www.post ...

  6. [Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

  7. 【并发编程】atomic 如何保证原子操作?分别用那几个方法?

    博主介绍: – 我是了 凡 微信公众号[了凡银河系]期待你的关注.未来大家一起加油啊~ 前言 之前学习了一些并发原语,已经认为差不多可以应对很多场景了,但是为什么还要学习原子操作呢?原来,在一些场景中 ...

  8. 数组字段查询不包含_不可不知的可变Java长数组

    前言 有时我们希望将把数据保存在单个连续的数组中,以便快速.便捷地访问数据,但这需要调整数组大小或者对其扩展.Java 数组不能调整大小,只用数组不足以达成目标.可变长原始类型数组需要自己实现.本文将 ...

  9. php 二维数组字段合并,PHP将二维数组某一个字段相同的数组合并起来的方法,二维数组数组_PHP教程...

    PHP将二维数组某一个字段相同的数组合并起来的方法,二维数组数组 本文实例讲述了PHP将二维数组某一个字段相同的数组合并起来的方法.分享给大家供大家参考,具体如下: 例子: array(3) { [0 ...

最新文章

  1. linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结
  2. 构建百万访问量电子商务网站之LVS负载均衡(前端四层负载均衡器)[连载之电子商务系统架构]...
  3. mysql 5.7 配置多实例 — 独立配置文件方式
  4. SPOJ- QTREE+HDU 3966(树链剖分裸题
  5. 1.5 编程基础之循环控制 09 奇数求和
  6. css毛玻璃效果白边_使用css模拟vista毛玻璃效果
  7. 计算机课Word自我介绍,第5课 用WORD写篇自我介绍.doc
  8. Python压缩新文件到已有ZIP文件
  9. [211渣硕] 腾讯/阿里/携程 详细NLP算法实习 面经
  10. LeetCode刷题——11. 盛最多水的容器
  11. MyBatis使用总结+整合Spring
  12. 【Spring-AOP】底层类AbstractAutoProxyCreator分析
  13. 时钟转盘html源代码
  14. Win10桌面图标箭头去掉的方法总结
  15. 砸盘、销号、解散社群,Merlin Lab“跑路三连”暴露了DeFi哪些问题?
  16. 申请美国大学计算机专业,低GPA如何申请美国大学计算机专业
  17. Redis简介及优势
  18. idm文件类型末知怎么办 idm文件类型error
  19. 请19级的童鞋们接收一下
  20. 机器周期、振荡周期、时钟周期、状态周期???

热门文章

  1. 【STM32】通用定时器(TIM2到TIM5)
  2. Cluster模式潜在问题及解决方案、Web服务综合解决方案
  3. Linux Centos7安装hadoop3.x安装流程(跪舔文)
  4. java input属性_如何在h:inputText中指定命令属性?
  5. mysql语句的左外链接_MySQL中的JOIN连接
  6. c++ 类的继承与派生
  7. 2018年长沙理工大学第十三届程序设计竞赛 G-逃离迷宫
  8. 在解决计算机主机,电脑主机噪音大怎么办 电脑主机噪音大解决方法【图文】...
  9. 7.使用reserve避免不必要的内存分配
  10. 系统相机裁剪比例_要不要买全画幅相机?