AtomicIntegerArray数组类型类
前一篇文章学习了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[]类型。
AtomicIntegerArray数组类型类的更多相关文章
- java中用spring实现数组类型输出
java 中的几个数组类型 1.Department类 package com.yy.collection; import java.util.List; import java.util.Map; ...
- Java学习笔记七——数组工具类Arrays
数组工具类Arrays Java提供的Arrays类里包含的一些static修饰的方法可以直接操作数组.若将里面的方法用熟的话,那开发效率会大大提高.下面介绍其中的方法. List<T> ...
- JS数组类型检测
在强类型语言,数组类型检测是非常容易的事情(typeof就可以解决),而在弱语言JS数据类型就很容易混淆了. JS中常见的数据类型有:number.string.boolean.undefined.f ...
- delphi 数组类型与数组指针的巧妙利用
{本例通过存取结构, 慢慢引入了数组类型与指针的一些使用方法; 其中六个小例子的测试内容和结果都是一样的. ---------------------------------------------- ...
- 数组工具类 - ArrayUtil.java
数组工具类,提供数组.对象之间转换的方法. 源码如下:(点击下载 - ArrayUtil.java .commons-lang-2.6.jar) import java.lang.reflect.Ar ...
- delphi 数组类型
数组类型 数组类型定义了一组指定类型的元素序列,在方括号中填入下标值就可访问数组中的元素.定义数组时,方括号也用来指定可能的下标值.例如,下面的代码中定义了一个有 24 个整数的数组:type ...
- 《JS权威指南学习总结--7.10 数组类型》
内容要点: 一.数组类型 判断它是否为数组通常非常有用.在ES5中,可以使用Array.isArray()函数来做这件事情: Array.isArray([]); //=>true Array. ...
- Yii的数组助手类
获取值 用原生PHP从一个对象.数组.或者包含这两者的一个复杂数据结构中获取数据是非常繁琐的. 你首先得使用isset 检查 key 是否存在, 然后如果存在你就获取它,如果不存在, 则提供一个默认返 ...
- FCL源码中数组类型的学习及排序函数Sort函数的分析
Array 是所有数组的基类ArrayList 解决了所有Array 类的缺点 能动态扩容, 但是类型不安全的,而是会有装箱与拆箱的性能开销List<T> 则是解决了ArrayLis ...
随机推荐
- web前端优化之内容优化
前端内容优化主要有以下几条: 1.尽量减少http请求 (1)合并文件,把多个css文件合并在一起: (2)css Sprites,把css相关的background元素进行背景图绝对定位: (3)图 ...
- Java 开源博客 Solo 1.4.0 发布 - 简化
Solo 1.4.0 正式发布了!这个版本主要是简化了配置项,修复了一些缺陷并改进了很多细节体验,感谢一直以来关注和支持我们的朋友! 只需一个命令即可启动(不需要安装数据库.部署容器):也可以通过 w ...
- The Willpower Instinct(自控力,意志力)
下面是我这几天在读斯坦福大学麦格尼格尔教授的<自控力>这本书的过程中摘抄的部分经典句子,发人深思!有助于帮助我们更好的了解自己. 00 导言:欢迎进入意志力入门 意志力:控制自己的注意力. ...
- hdu 1159 Common Subsequence(LCS)
Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- 05_zookeeper的ACL
[ACL概述] ACL:access control Lists,权限控制. * 针对节点可以设置相关的读写等权限,目的是为了保障数据安全性. * 权限permissions可以指定不同的权限范围以及 ...
- 【Android】修改包名
工程写的差不多了才发现原来用的包名还是自己尝试性的进行写代码的时候用到的.但apk的发布,google map api的申请等等方面都需要用到一个比较规范的包名.这就涉及到修改包名的问题. 包名一开始 ...
- 用虚拟信用卡注册Google Play开发者账号
本文首发于http://www.abcdsxg.cn/free/net/562 虚拟信用卡 首先介绍一下虚拟信用卡(Virtual Credit Card),顾名思义,虚拟就是没有实体卡,一般都是在提 ...
- canvas中的非零环绕原则
非零环绕原则: 如果需要判断某一个区域是否需要填充颜色. 就从该区域中随机的选取一个点. 从这个点拉一条直线出来, 一定要拉到图形的外面. 此时以该点为圆心.看穿过拉出的直线的线段. 如果是顺时针方向 ...
- ssh免密码登陆失败的原因
今天因为需要在两台服务器上进行ssh免登陆,所以安装网上的教程,ssh-keygen -t rsa,然后把相互的密钥加入到对方的authorized_keys. 问题是我们虽然这样做了,却一直要密码, ...
- Grunt 使用(一)基础搭建
jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用!废话不多说,直接上干货. 1.安装node.js并检查node -v 和 n ...