Java并发学习(八)-AtomicIntegerArray数组类型类
来源:互联网 发布:js图片视频轮播 编辑:程序博客网 时间:2024/06/11 22:50
前一篇文章学习了AtomicXXX基本数据类型类,可以为int,boolean或者reference类型,也就是单个元素的原子类。那么数组类型呢?
下面以AtomicIntegerArray
为例进行分析。
AtomicXXXArray包括三种具体类:AtomicIntegerArray
,AtomicLongArray
,AtomicReferenceArray
。
What is AtomicIntegerArray
具体的介绍,都已经在开头讲过了,AtomicIntegerArray
有以下特点:
- 可以存放int数值的原子性数组
- 以整个数组对象为单位,里面的元素操作都是原子性的
实现
从以前的文章分析可以了解,一般原子类的实现都是volatile+CAS的方式,那么AtomicIntegerArray也是么?
首先,作为原子性数组,里面肯定有个int类型数组,那数组是volatile类型么?
前面文章分析可以知道,如果把数组定义为volatile类型,那么其里面数组元素在读写方面是没有volatile语义。 可以参看:Java并发学习(二)-JMM 。
直接看代码中定义:
private final int[] array;
定义了一个final的int类型数组,final的内存语义则是使用时,一定是已经直接初始化或者通过构造方法初始化好的。
//获取int[]在内存中的初始地址。 private static final int base = unsafe.arrayBaseOffset(int[].class); //用来存储移位个数 private static final int shift; private final int[] array; //初始化变量。 static { int scale = unsafe.arrayIndexScale(int[].class); if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); //得出scale为2的几次方,即需要移位个数 shift = 31 - Integer.numberOfLeadingZeros(scale); } //检查第i个元素的地址值。 private long checkedByteOffset(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); return byteOffset(i); } //当前索引i*shift(偏移位置) + base(基础位置) private static long byteOffset(int i) { return ((long) i << shift) + base; } //获取第i个元素的值 public final int get(int i) { return getRaw(checkedByteOffset(i)); } //通过地址值来获取偏移量的元素值。 private int getRaw(long offset) { return unsafe.getIntVolatile(array, offset); } //用cas方式,在元素i的位置设置新值 public final void set(int i, int newValue) { unsafe.putIntVolatile(array, checkedByteOffset(i), newValue); }
核心代码可以看上面,具体都有注释,可能有点模糊,这里再说说核心思想:
我们知道,数组在内存中是连续存储的,如下:
并且数组里面各个元素类别都是相同的,所以占有的空间也都是一样大的,假设上面数组为int类型的array,并且array的地址为n,所以可以计算出array[1]为array+4,array[2]为
array+4*2,array[3]为array+4*3 。
所以这样在AtomicIntegerArray里面,我们可以通过base,i,scale和shift,能够计算出数组中任意元素的位置以及获取值,这样一来,对数组的操作就可以转化为对单个元素的操作。
开始被一个问题困扰了一会儿,array数组是final类型,保证了:
- array在使用的时候,已经初始化了
- array不能再重新指向其他对象
但是,array数组里面并不是volatile类型的,能确保可见性么?
我们再来看看它的get方法和set方法:
get方法:
public final int get(int i) { return getRaw(checkedByteOffset(i)); } //volatile的get private int getRaw(long offset) { return unsafe.getIntVolatile(array, offset); }
set方法:
//volatile的set public final void set(int i, int newValue) { unsafe.putIntVolatile(array, checkedByteOffset(i), newValue); } //lazySet,即普通set,性能高 public final void lazySet(int i, int newValue) { unsafe.putOrderedInt(array, checkedByteOffset(i), newValue); } //原子性的获取并且set public int getAndSet(int i, int newValue) { return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue); }
如上我们可以看到,调用的都是unsafe里面具有volatile语义的方法,也就是整个通过内存xia地址对数组元素的操作,也是有volatile语义的,即具有可见性。
AtomicLongArray和AtomicObjectArray
这两者与AtomicIntegerArray实现基本一致,只是数组对象分别为long[]和Object[]类型。
参考资料:
1. jdk
2. http://hg.openjdk.java.net/jdk8u/jdk8u20/hotspot/file/190899198332/src/share/vm/prims/unsafe.cpp
- Java并发学习(八)-AtomicIntegerArray数组类型类
- 【实战Java高并发程序设计 4】数组也能无锁:AtomicIntegerArray
- 笑谈java并发编程三之AtomicIntegerArray介绍
- Java 原子操作类详解(AtomicInteger、AtomicIntegerArray等)
- AtomicIntegerArray
- Java并发学习笔记(八)-LinkedBlockingQueue
- 并发编程--AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray
- java学习初探八之数组应用
- 【Java学习4.5】数组类型
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap
- [Java并发包学习八]深度剖析ConcurrentHashMap-java1.7
- 常用正则表达式
- codeforce 448 B. XK Segments
- Activity生命周期
- Des加密理解
- php将连续回车(换行)、空格正则替换为1个
- Java并发学习(八)-AtomicIntegerArray数组类型类
- Mybatis全部标签
- ES6/ES2015(下)
- 大数据篇_Hadoop入门介绍
- TensorFlow基础4:四种类型数据的读取流程及API讲解和代码实现
- 梯度下降算法实现
- 面向对象-接口 interface关键字
- HDFS NameNode重启优化
- [新手向] c++大数运算 (1)