前一篇文章学习了AtomicXXX基本数据类型类,可以为int,boolean或者reference类型,也就是单个元素的原子类。那么数组类型呢? 
下面以AtomicIntegerArray为例进行分析。 
AtomicXXXArray包括三种具体类:AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray

What is AtomicIntegerArray

具体的介绍,都已经在开头讲过了,AtomicIntegerArray有以下特点:

  • 可以存放int数值的原子性数组
  • 以整个数组对象为单位,里面的元素操作都是原子性的

实现

从以前的文章分析可以了解,一般原子类的实现都是volatile+CAS的方式,那么AtomicIntegerArray也是么? 
首先,作为原子性数组,里面肯定有个int类型数组,那数组是volatile类型么? 
前面文章分析可以知道,如果把数组定义为volatile类型,那么其里面数组元素在读写方面是没有volatile语义。 可以参看:Java并发学习(二)-JMM 。

直接看代码中定义:

  1. private final int[] array;

定义了一个final的int类型数组,final的内存语义则是使用时,一定是已经直接初始化或者通过构造方法初始化好的。

  1. //获取int[]在内存中的初始地址。
  2. private static final int base = unsafe.arrayBaseOffset(int[].class);
  3. //用来存储移位个数
  4. private static final int shift;
  5. private final int[] array;
  6. //初始化变量。
  7. static {
  8. int scale = unsafe.arrayIndexScale(int[].class);
  9. if ((scale & (scale - 1)) != 0)
  10. throw new Error("data type scale not a power of two");
  11. //得出scale为2的几次方,即需要移位个数
  12. shift = 31 - Integer.numberOfLeadingZeros(scale);
  13. }
  14. //检查第i个元素的地址值。
  15. private long checkedByteOffset(int i) {
  16. if (i < 0 || i >= array.length)
  17. throw new IndexOutOfBoundsException("index " + i);
  18. return byteOffset(i);
  19. }
  20. //当前索引i*shift(偏移位置) + base(基础位置)
  21. private static long byteOffset(int i) {
  22. return ((long) i << shift) + base;
  23. }
  24. //获取第i个元素的值
  25. public final int get(int i) {
  26. return getRaw(checkedByteOffset(i));
  27. }
  28. //通过地址值来获取偏移量的元素值。
  29. private int getRaw(long offset) {
  30. return unsafe.getIntVolatile(array, offset);
  31. }
  32. //用cas方式,在元素i的位置设置新值
  33. public final void set(int i, int newValue) {
  34. unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
  35. }

核心代码可以看上面,具体都有注释,可能有点模糊,这里再说说核心思想: 
我们知道,数组在内存中是连续存储的,如下: 

并且数组里面各个元素类别都是相同的,所以占有的空间也都是一样大的,假设上面数组为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方法:

  1. public final int get(int i) {
  2. return getRaw(checkedByteOffset(i));
  3. }
  4. //volatile的get
  5. private int getRaw(long offset) {
  6. return unsafe.getIntVolatile(array, offset);
  7. }

set方法:

  1. //volatile的set
  2. public final void set(int i, int newValue) {
  3. unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
  4. }
  5. //lazySet,即普通set,性能高
  6. public final void lazySet(int i, int newValue) {
  7. unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
  8. }
  9. //原子性的获取并且set
  10. public int getAndSet(int i, int newValue) {
  11. return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue);
  12. }

如上我们可以看到,调用的都是unsafe里面具有volatile语义的方法,也就是整个通过内存xia地址对数组元素的操作,也是有volatile语义的,即具有可见性。

AtomicLongArray和AtomicObjectArray

这两者与AtomicIntegerArray实现基本一致,只是数组对象分别为long[]和Object[]类型。

AtomicIntegerArray数组类型类的更多相关文章

  1. java中用spring实现数组类型输出

    java 中的几个数组类型 1.Department类 package com.yy.collection; import java.util.List; import java.util.Map; ...

  2. Java学习笔记七——数组工具类Arrays

    数组工具类Arrays Java提供的Arrays类里包含的一些static修饰的方法可以直接操作数组.若将里面的方法用熟的话,那开发效率会大大提高.下面介绍其中的方法. List<T> ...

  3. JS数组类型检测

    在强类型语言,数组类型检测是非常容易的事情(typeof就可以解决),而在弱语言JS数据类型就很容易混淆了. JS中常见的数据类型有:number.string.boolean.undefined.f ...

  4. delphi 数组类型与数组指针的巧妙利用

    {本例通过存取结构, 慢慢引入了数组类型与指针的一些使用方法; 其中六个小例子的测试内容和结果都是一样的. ---------------------------------------------- ...

  5. 数组工具类 - ArrayUtil.java

    数组工具类,提供数组.对象之间转换的方法. 源码如下:(点击下载 - ArrayUtil.java .commons-lang-2.6.jar) import java.lang.reflect.Ar ...

  6. delphi 数组类型

    数组类型 数组类型定义了一组指定类型的元素序列,在方括号中填入下标值就可访问数组中的元素.定义数组时,方括号也用来指定可能的下标值.例如,下面的代码中定义了一个有 24 个整数的数组:type     ...

  7. 《JS权威指南学习总结--7.10 数组类型》

    内容要点: 一.数组类型 判断它是否为数组通常非常有用.在ES5中,可以使用Array.isArray()函数来做这件事情: Array.isArray([]); //=>true Array. ...

  8. Yii的数组助手类

    获取值 用原生PHP从一个对象.数组.或者包含这两者的一个复杂数据结构中获取数据是非常繁琐的. 你首先得使用isset 检查 key 是否存在, 然后如果存在你就获取它,如果不存在, 则提供一个默认返 ...

  9. FCL源码中数组类型的学习及排序函数Sort函数的分析

    Array 是所有数组的基类ArrayList 解决了所有Array 类的缺点    能动态扩容, 但是类型不安全的,而是会有装箱与拆箱的性能开销List<T> 则是解决了ArrayLis ...

随机推荐

  1. VC编程操作word2010生成表格

    作者:朱金灿 来源:http://blog.csdn.net/clever101 一.   右键单击工程节点,然后选择添加类,如下图: 二.   添加TypeLib中的MFC类,如下图: 三.   选 ...

  2. 10_Redis实现分布式锁

    来源:吴兆锋, https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/ 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁: ...

  3. Python爬虫教程-30-Scrapy 爬虫框架介绍

    从本篇开始学习 Scrapy 爬虫框架 Python爬虫教程-30-Scrapy 爬虫框架介绍 框架:框架就是对于相同的相似的部分,代码做到不出错,而我们就可以将注意力放到我们自己的部分了 常见爬虫框 ...

  4. c# 修改winform中app.config的配置值

    public bool ChangeConfig(string AppKey,string AppValue) { bool result = true; try { XmlDocument xDoc ...

  5. Python初学者第二天 用户输入和注释

    2day Python基础语法: 1.用户输入和注释 用户输入:   代码注释:# 注释部分不会被执行,或用来帮助理清代码逻辑   2.数据类型:数字 int:整数   long:长整形  注:Pyt ...

  6. ping -l 1000 -t 与ping -t的区别

    windows -l 1000的意思是规定发送的包的大小是1000字节如果不加这个参数的话,就发送包默认为32字节还有-t就是一直发送,直到手动停止

  7. ubuntu桌面便签 sticky note, xpad

    sudo apt-get install xpad 软件有一个选项,叫做Show window decorations,显示窗口的标题栏.

  8. ZT 俞敏洪:2014我要闭嘴 相信未来不是梦

    俞敏洪:2014我要闭嘴 相信未来不是梦 手机免费访问www.cnfol.com2013年12月11日 08:38 中国企业家网 查看评论 字体:小  中  大中金在线微博微信加关注 扫描二维码 关注 ...

  9. Geekforgeek week1

    1. is palindrome solution 1: check to reverse the digit, if they are the same number https://www.gee ...

  10. Android webview 点击超链接打开新的webview

    webview.setWebViewClient(new webViewClient() { HitTestResult hit = view.getHitTestResult(); if (hit ...