文档章节

Java多线程之JUC原子类 - 以原子方式操作数组AtomicLongArray

 何如泛轻舟
发布于 2018/08/31 15:56
字数 1149
阅读 21
收藏 0

一、AtomicLongArray的介绍

    AtomicLongArray是JUC提供的以原子方式操作数组的一个类,存储在AtomicLongArray中的数组元素能够以原子方式进行更新,它原子变量的实现依赖于sun.misc的Unsafe类提供的CAS操作和volatile的多线程内存可见性语义,下面我们看下该类的数据结构。

二、AtomicLongArray数据结构

public class AtomicLongArray implements java.io.Serializable {
    private static final long serialVersionUID = -2308431214976778248L;
    // unsafe变量是AutomicLongArray实现数组原子化更新的核心,数组元素的修改操作由unsafe的CAS相关操作完成
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // base是数组首个元素偏移地址
    private static final int base = unsafe.arrayBaseOffset(long[].class);
    // 数组元素的偏移量
    private static final int shift;
    // 保存元素的数组
    private final long[] array;

    static {
        // 获取数组元素的增量偏移
        int scale = unsafe.arrayIndexScale(long[].class);
        // 判断是不是2的倍数
        if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
        // 获取long型元素的偏移量
        shift = 31 - Integer.numberOfLeadingZeros(scale);
    }

}

 

三、AtomicLongArray源码解析

1 - long checkAndByteOffSet(int i) 方法

    checkAndByteOffset(int i)方法主要用于判断索引值是否越界,若越界则抛出越界异常,否则计算索引值对应的元素在数组中的内存偏移量

    private long checkedByteOffset(int i) {
        if (i < 0 || i >= array.length)
            throw new IndexOutOfBoundsException("index " + i);

        return byteOffset(i);
    }

    方法首先校验了索引的范围,若索引i越界则抛出IndexOutOfBoundsException异常,否则调用byteOffSet方法,我们进入byteOffset方法源码内部看下方法内部做了什么

    private static long byteOffset(int i) {
        return ((long) i << shift) + base;
    }

    方法很简单,根据索引下标i计算出每个元素的内存地址,元素内存地址=首地址偏移+每个元素的相对于数组偏移,每个数组元素相对数组的偏移量等于元素所占内存8*数组下标i。

 

2 -  long get(int i)方法 - 以原子方式获取数组指定索引位置元素

    public final long get(int i) {
        return getRaw(checkedByteOffset(i));
    }

        方法逻辑不难,首先调用checkedByteOffset方法校验数组的索引下标i,校验通过返回对应下标元素的内存地址,接着将该地址作为参数调用getRow方法,进入该方法源码:

    private long getRaw(long offset) {
        return unsafe.getLongVolatile(array, offset);
    }

    该方法在内部调用了unsafe.getLongVolitile方法获取数组指定下标i的元素。

    long get(int i)方法的基本逻辑总结如下:1)校验数组下标i,若越界抛出异常,否则获取索引下标元素的内存地址;2)基于元素的内存地址获取指定下标的数组元素。

 

3 - void set(int i, long value) - 以原子方式设置数组指定下标位置值

    /**
     * 以原子方式设置数组指定下标位置值为newValue
     */
    public final void set(int i, long newValue) {
        unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
    }

        set方法的基本逻辑与get类似,先校验数组下标i,若校验通过返回数组下标位置的地址,基于该地址和内部数组引用array设置新值newValue.

 

4 - long incrementAndGet方法 - 以原子方式在指定下标i元素加1,返回更新后的值

    /**
     * 以原子方式在指定下标i元素加1,返回更新后的值
     */
    public final long incrementAndGet(int i) {
        return getAndAdd(i, 1) + 1;
    }

    看下getAndAdd方法源码

    public final long getAndAdd(int i, long delta) {
        return unsafe.getAndAddLong(array, checkedByteOffset(i), delta);
    }

    到这里就清楚了,该方法首先对数组索引下标i做了范围校验,校验通过获取数组下标位置的地址,基于该地址调用unsafe的getAndAddLong对该位置元素使用CAS操作更新,注意此时返回的long值时更新前的所以我们在调用处incrementAndGet方法还要加1。

5 - void lazySet方法 - 延时更新数组下标元素,优先保证数据的修改操作,而降低对可见性的要求

    /**
     * 更新数组指定下标i处的值为newValue,与set的区别在于它是延时而不是立即更新,适用于对实时性要求不高的场景
     */
    public final void lazySet(int i, long newValue) {
        unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
    }

6 - 其他方法

    其他方法逻辑类似就不一一分析了

© 著作权归作者所有

粉丝 15
博文 64
码字总数 107681
作品 0
杭州
后端工程师
私信 提问
java高并发系列 - 第23天:JUC中原子类,一篇就够了

这是java高并发系列第23篇文章,环境:jdk1.8。 本文主要内容 JUC中的原子类介绍 介绍基本类型原子类 介绍数组类型原子类 介绍引用类型原子类 介绍对象属性修改相关原子类 预备知识 JUC中的原...

路人甲Java
08/07
0
0
java.util.concurrent.atomic原子操作类包

这个包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打...

宋哥陈
2015/04/13
88
0
Java多线程之JUC原子类AtomicLong

一、AtomicLong的介绍 我们都知道在java中long类型变量占用的字节数是8也就是64位,而在32位的操作系统对64位的数据读写要分成两步完成,每一步取32位操作。这样的话JVM就不能保证对long和d...

老韭菜
2018/07/25
10
0
AtomicInteger原理

AtomicInteger的原理 java的并发原子包里面提供了很多可以进行原子操作的类,比如: AtomicInteger AtomicBoolean AtomicLong AtomicReference 等等,一共分为四类:原子更新基本类型(3个)...

王小冬
2018/05/27
0
0
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
695
1

没有更多内容

加载失败,请刷新页面

加载更多

Android -------- kotlin插件神器Json直接生成javaBean

这是一个data class从JSON字符串生成Kotlin 的插件,换句话说,是一个将JSON字符串转换为Kotlin data class(Json到Kotlin)的插件 在使用Kotlin进行开发的时候,我们需要经常对Json数据做解析...

切切歆语
4分钟前
8
0
1、Spring注解开发,第一天

第一天:Spring annotation开发 目录:1、@Configuration与@Bean给容器注册组件 2、@ConponentScan自动扫描注解 一、@Configuration与@Bean给容器注册组件 1、旧版本中创建配置文件和Bean //...

有一个小阿飞
12分钟前
11
0
斯坦福博弈论笔记整理活动的任务已重新划分,望周知

参与方式:https://github.com/apachecn/stanford-game-theory-notes-zh/blob/master/CONTRIBUTING.md 整体进度:https://github.com/apachecn/stanford-game-theory-notes-zh/issues/1 项目......

ApacheCN_飞龙
13分钟前
6
0
使用HTML5 canvas完成的一个网页白板

该代码能够使用canvas对象完成的一个基本功能。仅供大家参考。 <html> <head> <meta http-equiv="Content-Type" contentType="text/html; charset=UTF-8" %> <title>Title</title> <script t......

前端老手
15分钟前
4
0
web漏洞之xss(学习记录)

xss又名跨站脚本攻击,是一种注入攻击,当web应用对用户输入过滤不严格,攻击者写入恶意的脚本代码(HTML、JavaScript)到网页中时,如果用户访问了含有恶意代码的页面,恶意脚本就会被浏览器...

半缘修道半缘君丶
17分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部