JUC学习篇二:AtomicLong与AtomicLongArray及其他Atomic工具类扩展

1、背景:java原生定义的八大基本数据类型是线程不安全的,毕竟没有任何封装,除非自己加上一些关键字或者锁…

2、考虑到java并发,解决一般性的并发问题,java官方在JUC的包内加了一些封装了基本类型的类,同时维护了他们一定程度上的线程安全

3、前奏:我们以前了解,java并发及多线程资源共享是存在隐患的,至于具体是什么这里不叙说,网上百度,教程多多。其中有一个关键字尤其重要,它就是 volatile

4、volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读(以原子的方式进行执行,具体更多了解去百度了解,这个东西的原理有那么复杂)

5、而JUC为我们提供了一系列封装volatile修饰的变量的类,下面一一讲解:

1、AtomicLong

看看这个类的源码
在这里插入图片描述
可以简单理解就是在为了达到线程安全给基本类型套了层皮,使其具有原子操作能力
一些较为常用的函数

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;

public class TimeUtilsTest {

    public static void main(String[] args){
        // 实例化一个AtomicLong类实例,传入一个初始long类型的值
        // 注意:无参构造时的初始值是 0
        AtomicLong atomicLong = new AtomicLong(10);

        // 获取这个被volatile修饰的long值
        System.out.println("get():"+atomicLong.get());

        // 四则运算,加法,并返回新的结果值
        System.out.println("addAndGet():"+atomicLong.addAndGet(40));

        //设置一个新的值,并且返回旧的值
        System.out.println("getAndSet(): "+atomicLong.getAndSet(10));

        //比较是否和所给的预期值一致,如果一致就修改为新的值
        // 10 是预期值,如果value的值就是10,则将value值改为100,反之不变value的值,
        //返回一个boolean值,表示value值是否和预期值一致
        System.out.println("compareAndSet(): "+atomicLong.compareAndSet(10, 100));

        //先获取当前value的值,再将当前值减一,返回是修改前的value值
        System.out.println("getAndDecrement(): "+atomicLong.getAndDecrement());
        //以原子的方式将value值减1再返回修改后的value值,原子方式是指:要么运行成功,要么运行失败!
        System.out.println("decrementAndGet(): "+atomicLong.decrementAndGet());
        
        //先获取当前value的值,再将当前值加一,返回是修改前的value值
        System.out.println("getAndIncrement(): "+atomicLong.getAndIncrement());
        //以原子的方式将value值加1再返回修改后的value值,原子方式是指:要么运行成功,要么运行失败!
        System.out.println("incrementAndGet(): "+atomicLong.incrementAndGet());

    }
}

运行结果截图:
在这里插入图片描述

PS: AtomicBoolean、AtomicInteger用法和上面类似,就不一一列举
但是对于AtomicInteger这个int的封装类,还是有一定注意一下,就是它的compareAndSet方法
在这里插入图片描述
在这里插入图片描述
底层方法是native修饰的(其他语言开发的,一般是c/c++),这个注意一下就可以,具体知识读者可以自行探索,下面给下简单的实例方法

AtomicBoolean atomicBoolean = new AtomicBoolean(true);
AtomicInteger atomicInteger = new AtomicInteger(20);

2、AtomicLongArray

我们看看这个类的源码
在这里插入图片描述
诶,发现了一个很奇怪的现象,这个类既然内部封装了线程操作安全的数组,可是也没见到数组是线程安全的,和我们一般创建的不是一样的吗?
其实啊,它这里是引用了一种新的java原生方法

private static final VarHandle AA
        = MethodHandles.arrayElementVarHandle(long[].class);

就是这个VarHandle,这是java 9引入的一个类,这里就作简单介绍:)

  • 用于更加细粒度的控制内存排序。在安全性、可用性
  • 性能更优
  • 可以与任何字段、数组元素或静态变量关联,支持在不同访问模型下对这些类型变量的访问,包括一些简单的 Read/Write 访问,volatile 类型的 Read/Write 访问,和 CAS(compare and swap)等

其实说这么多就是表达一点,为一个普通的属性赋值原子操作能力,而操作的对象自然就是普通的long数组了

本人太菜了,只了解这些,具体了解可以自行百度

1、两个有参构造方法(打错字了,是传入,(。・_・。)ノI’m sorry~)
在这里插入图片描述
常使用方法:

import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.*;

public class TimeUtilsTest {

    public static void main(String[] args){
        // 以下都简称这个类为数组
        // 对long数组进行封装,使其变为按照原子性的线程安全类型的数据结构
        AtomicLongArray array = new AtomicLongArray(new long[]{1,2,0,5});
        //  获取内部数组的长度
        System.out.println("length(): "+array.length());

        //将数组下标为i的值修改一个新的值,返回类型是void,下标从0开始
        array.set(0,100);

        // 将数组下标为i的值和一个值相加, 并返回相加后的值
        System.out.println("addAndGet(): "+array.addAndGet(2, 20));

        // 第一个是下标,第二个是预期值,第三个是将要修改的新值
        // 判断数组下标为i的值是否和预期值一致,如果一致就修改为新值
        // 返回值是Boolean,代表是否和预期值一致
        //该函数缩小是著名的CAS,其有效地说明了
        // “我认为位置0应该包含值100;如果包含该值,则将10放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可"
        System.out.println("compareAndSet(): "+array.compareAndSet(0, 100, 10));

        // 获取数组下标为i的值
        System.out.println("get(): "+array.get(0));

        
        //将数组下标为i的值先取出,再讲数组下标为i的值减一,返回修改前的值
        System.out.println("getAndDecrement(): "+array.getAndDecrement(0));
        //以原子方式将数组下标为i的值先减一。再取出,返回修改后的值
        System.out.println("decrementAndGet(): "+array.decrementAndGet(0));

        //将数组下标为i的值先取出,再讲数组下标为i的值加一,返回修改前的值
        System.out.println("getAndIncrement(): "+array.getAndIncrement(0));
        //以原子方式将数组下标为i的值先加一。再取出,返回修改后的值
        System.out.println("incrementAndGet(): "+array.incrementAndGet(0));
    }
}

在这里插入图片描述

/*
总结一点:其实 ++i 和 i++ 或者- -,都不是原子操作
它内部都是通过CAS(compareAndSet)来实现的

*/
看下面源代码就晓得了
在这里插入图片描述
在这里插入图片描述
而Atomic的引用下次再更新,累死了,脑壳痛

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌晨小街

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值