java编程基础教程idea激活码(Java原子操作第八章)

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境
  • JDK v11
  • IntelliJIDEA v2018.3
友情提示
  • 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
  • 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!
1.温故知新

前面在《“全栈2019”Java原子操作第三章:比较并交换CAS技术详解》一章中介绍了什么是比较并交换CAS技术

在《“全栈2019”Java原子操作第四章:AtomicBoolean介绍与使用》一章中介绍了什么是原子操作类AtomicBoolean

在《“全栈2019”Java原子操作第五章:AtomicInteger介绍与使用》一章中介绍了什么是原子操作类AtomicInteger

在《“全栈2019”Java原子操作第六章:AtomicInteger灵活的运算方式》一章中介绍了使用原子操作类AtomicInteger的方法实现更灵活的运算方式

在《“全栈2019”Java原子操作第七章:AtomicLong介绍与使用》一章中介绍了什么是原子操作类AtomicLong

现在介绍原子操作类AtomicReference<V>

2.什么是原子操作类?

顾名思义,原子操作类就是实现了原子操作的类。

原子操作的概念和必备知识在该系列的《“全栈2019”Java原子操作第一章:内存可见性volatile关键字解析》和《“全栈2019”Java原子操作第二章:i 是原子操作吗?何为原子性》以及《“全栈2019”Java原子操作第三章:比较并交换CAS技术详解》三章中已经详细介绍过了,这里就不再赘述。不清楚的小伙伴请前去查阅相关章节。

2.AtomicReference<V>简介

对于学过该系列的第一、二、三章的小伙伴来说,原子操作类就显得简单很多,而且里面的原理已经掌握得差不多了,所以本章就简单来介绍一下原子操作类之一:AtomicReference<V>。

AtomicReference<V>类很简单,它有两个构造方法:

java编程基础教程idea激活码(Java原子操作第八章)(1)

如下:

  • AtomicReference()
  • AtomicReference​(V initialValue)

这两个构造方法都比较常用。

第二个构造方法AtomicReference​(V initialValue)可以指定初始值。

下面我们就来用一用AtomicReference<V>。

3.AtomicReference<V>应用场景

AtomicReference<V>应用也比较广泛,只要是对象操作是原子的,都可以使用到AtomicReference<V>。

例如,我们之前说到的计数器,那时用的是AtomicInteger,没有用Integer,那是因为Integer不带原子操作。现在可以用Integer了,因为只需将Integer与AtomicReference<V>结合即可,这样我们以原子的方式更新Integer对象,也就不存在并发问题了。

如果大家有更多关于AtomicReference<V>的应用场景请在评论区留言,谢谢。

下面,来看看未使用AtomicReference<V>的时候会是怎样。

例子是全局计数器。

首先,我们创建一个全局计数器类:

java编程基础教程idea激活码(Java原子操作第八章)(2)

然后,将其构造方法进行私有化,目的是不让创建对象,只能使用其静态方法:

java编程基础教程idea激活码(Java原子操作第八章)(3)

接着,定义一个Integer类型的变量记录当前生成的计数器:

java编程基础教程idea激活码(Java原子操作第八章)(4)

然后,定义一个方法来获取当前计数器的值:

java编程基础教程idea激活码(Java原子操作第八章)(5)

接着,再定义一个方法来递增计数器的值:

java编程基础教程idea激活码(Java原子操作第八章)(6)

全局计数器类写好了。

接下来,我们去试试全局计数器。

在Main类中创建一个计数任务:

java编程基础教程idea激活码(Java原子操作第八章)(7)

接着,在run方法里面调用全局计数器对象的递增方法:

java编程基础教程idea激活码(Java原子操作第八章)(8)

run()方法书写完毕。

然后,我们创建100个线程去执行计数任务:

java编程基础教程idea激活码(Java原子操作第八章)(9)

最后,等这100个线程都执行完计数任务任务以后,我们再次获取计数器的当前值:

java编程基础教程idea激活码(Java原子操作第八章)(10)

如果当前计数器的值是100,则说明每个线程都有自己唯一的计数,都是不同的;

如果当前计数器的值不是100,则说明有计数相同的线程,全局计数器这个类就有问题。

不过在此之前需要睡1秒钟,目的是等这100个线程执行完毕之后我们再获取当前计数器的值:

java编程基础教程idea激活码(Java原子操作第八章)(11)

例子书写完毕。

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(12)

从运行结果来看,不符合预期。当前计数不为100,说明全局计数器这个类是有问题的。

怎么解决?

这时我们的AtomicReference<V>类派上用场了。

我们只需用AtomicReference<Integer>替换Integer类型即可:

java编程基础教程idea激活码(Java原子操作第八章)(13)

因为AtomicReference<Integer>替换Integer,所以获取当前计数器的值的方法和递增当前计数器的值的方法都得改变。

先是获取当前计数器的值的方法:

java编程基础教程idea激活码(Java原子操作第八章)(14)

然后是递增当前计数器的值的方法:

java编程基础教程idea激活码(Java原子操作第八章)(15)

对于学过前面几章的小伙伴来说,get()方法和getAndUpdate(UnaryOperator<V> updateFunction)方法不陌生,get()方法是用来获取value的当前值;getAndUpdate(UnaryOperator<V> updateFunction)方法是用来更新value对象当前值的,我们可以自定义更新方式。

注:getAndUpdate(UnaryOperator<V> updateFunction)方法在下面小节会有详细讲解。

例子改写完毕。

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(16)

从运行结果来看,符合预期。当前计数为100,全局计数器这个类的问题得到了解决。

当然了,除了给Java已经存在的对象赋予原子性,我们还可以给自定义对象赋予原子性。

下面,我们就来一个自定义对象Person:

java编程基础教程idea激活码(Java原子操作第八章)(17)

然后,在Person类中定义两个属性,姓名和年龄:

java编程基础教程idea激活码(Java原子操作第八章)(18)

接着,我们给Person类增加一个有参构造方法,而且还要保留无参构造方法:

java编程基础教程idea激活码(Java原子操作第八章)(19)

最后,给Person类中的name和age属性提供getter/setter方法:

java编程基础教程idea激活码(Java原子操作第八章)(20)

自定义对象写好了。

下面就用AtomicReference<V>与Person类来说说AtomicReference<V>类里面几个常用方法及源码。

对于学过《“全栈2019”Java原子操作第五章:AtomicInteger介绍与使用》和《“全栈2019”Java原子操作第七章:AtomicLong介绍与使用》两章的小伙伴来说,掌握下面的内容轻而易举,因为变化的仅仅是将int、long类型变为对象类型。

注:因为下面内容在之前章节中讲过太多次,所以此次内容会得到精简,以便阅读。

4.获取当前值get()方法

get()方法的作用是获取对象的当前值;

例子:

java编程基础教程idea激活码(Java原子操作第八章)(21)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(22)

从运行结果来看,符合预期。

5.设置新值set​(V newValue)方法

set​(V newValue)方法的作用是设置对象的当前值。参数newValue是我们可以指定的新值。

例子:

java编程基础教程idea激活码(Java原子操作第八章)(23)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(24)

从运行结果来看,符合预期。

6.返回更新前的值getAndUpdate(UnaryOperator<V> updateFunction)方法

getAndUpdate(UnaryOperator<V> updateFunction)方法的作用是返回更新前的值。

例子:

java编程基础教程idea激活码(Java原子操作第八章)(25)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(26)

从运行结果来看,符合预期。即使在getAndUpdate(UnaryOperator<V> updateFunction)方法中设置了新值,但方法则返回的是更新前的值。

7.返回更新后的值updateAndGet(UnaryOperator<V> updateFunction)方法

updateAndGet(UnaryOperator<V> updateFunction)方法的作用是返回更新后的值。

例子:

java编程基础教程idea激活码(Java原子操作第八章)(27)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(28)

从运行结果来看,符合预期。我们在updateAndGet(UnaryOperator<V> updateFunction)方法中设置了新值,方法即时返回了新值。

8.返回自定义运算方式更新前的值getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction)方法

getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction)方法的作用是返回自定义运算方式更新前的值。

例子:

java编程基础教程idea激活码(Java原子操作第八章)(29)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(30)

从运行结果来看,符合预期。原值为“Tom:18”,然后我们在getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction)方法中设置了新值“Jack:23”,方法返回了更新前的值“Tom:18”。

9.返回自定义运算方式更新后的值accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction)方法

accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction)方法的作用是返回自定义运算方式更新前的值。

例子:

java编程基础教程idea激活码(Java原子操作第八章)(31)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(32)

从运行结果来看,符合预期。原值为“Tom:18”,然后我们在accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction)方法中设置了新值“Jack:23”,方法返回了更新后的值“Jack:23”。

10.CAS算法体现

我们之前在《“全栈2019”Java原子操作第三章:比较并交换CAS技术详解》一章中学习过什么是CAS算法。

在AtomicReference<V>类中也有体现:

java编程基础教程idea激活码(Java原子操作第八章)(33)

compareAndSet(V expectedValue, V newValue)方法的作用是当value==expectedValue时,就将newValue赋给value,否则什么也不做。

例子:

java编程基础教程idea激活码(Java原子操作第八章)(34)

运行程序,执行结果:

java编程基础教程idea激活码(Java原子操作第八章)(35)

从运行结果来看,符合预期。

当然了,你也可以将预期值改为一个非原值的数,这样赋值就不成功。

最后,希望大家可以把这个例子照着写一遍,然后再自己默写一遍,方便以后碰到类似的面试题可以轻松应对。

祝大家编码愉快!

GitHub

本章程序GitHub地址:https://github.com/gorhaf/Java2019/tree/master/Thread/atomic/AtomicReference<V>

总结
  • AtomicReference<V>是一个以原子方式操作对象的类。
  • get()方法的作用是获取对象的当前值;
  • set​(V newValue)方法的作用是设置对象的当前值。参数newValue是我们可以指定的新值。
  • getAndUpdate(UnaryOperator<V> updateFunction)方法的作用是返回更新前的值。
  • updateAndGet(UnaryOperator<V> updateFunction)方法的作用是返回更新后的值。
  • getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction)方法的作用是返回自定义运算方式更新前的值。
  • accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction)方法的作用是返回自定义运算方式更新前的值。
  • compareAndSet(V expectedValue, V newValue)方法的作用是当value==expectedValue时,就将newValue赋给value,否则什么也不做。

至此,Java中AtomicReference<V>相关内容讲解先告一段落,更多内容请持续关注。

答疑

如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。

上一章

“全栈2019”Java原子操作第七章:AtomicLong介绍与使用

下一章

“全栈2019”Java原子操作第九章:atomic包下原子数组介绍与使用

学习小组

加入同步学习小组,共同交流与进步。

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划

关注我们,加入“全栈工程师学习计划”。

java编程基础教程idea激活码(Java原子操作第八章)(36)

版权声明

原创不易,未经允许不得转载!

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页