您的位置 首页 java

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

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境

  • JDK v11
  • IntelliJIDEA v2018.3

友情提示

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

1.温故知新

前面在 一章中介绍了 Java多线程基础知识总结及学习资料

在 一章中介绍了 内存可见性volatile关键字

在 一章中介绍了 什么是原子性

在 一章中介绍了 什么是比较并交换CAS技术

在 一章中介绍了 什么是原子操作类AtomicBoolean

现在介绍 原子操作类AtomicInteger

2.什么是原子操作类?

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

原子操作的概念和必备知识在前三章已经详细介绍过了,这里就不在赘述。不清楚的小伙伴请前去查阅相关章节。

2. AtomicInteger 简介

对于学过 和 以及 三章的小伙伴来说,原子操作类就显得简单很多,而且里面的原理已经掌握得差不多了,所以本章就简单来介绍一下原子操作类之一:AtomicInteger。

AtomicInteger是一个以原子方式操作int值的类。

先简单来看一下AtomicInteger类长什么样:

这里需要注意的是,AtomicInteger它继承了Number类,说明它不能替代Integer类,只是扩展了Number类。

AtomicInteger类很简单,它有两个 构造方法

如下:

  • AtomicInteger()
  • AtomicInteger​(int initialValue)

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

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

下面我们就来用一用AtomicInteger。

3. AtomicInteger 应用场景

例如, 我们某些应用需要计数,那么就可以用到AtomicInteger。

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

下面,来看看未使用AtomicInteger的时候会是怎样。

首先,来一个全局 计数器 Counter类:

然后,将这个全局计数器设为单例:

接着,计数器Counter类需要有一个变量来记录当前值:

然后,我们需要提供一个获取计数器的当前值的方法:

接着,计数器Counter类里面的值需要递增,得提供一个递增方法:

好了,计数器Counter类书写完毕。

接下来,我们来用一用计数器Counter类。

我们来书写Main类。

在Main类中创建一个计算任务,用于递增计数器里面的值:

在run()方法里面调用计数器的方法:

run()方法书写完毕。

接着,我们循环创建100个 线程 去执行这个计算任务:

目的就是看看在多线程并发情况下,计数器Counter类有没有问题。

如果结果是100那么说明没有问题,如果结果不是100说明有问题。

最后,我们来获取线程执行完之后的计数器的值:

不过在此之前我们想等这100个线程都执行完,所以在获取计数器的值之前等1秒钟:

例子书写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。结果为100,计数器没有问题。

计数器真的没有问题吗?

我们来将上述程序改改再看。

在计算任务中,让每个线程计算前睡100毫秒:

例子改写完毕。

运行程序,执行结果:

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

这次结果不为100,为什么还符合预期呢?

因为我们这次就是让结果不为100,来说明计数器是有问题的,所以此次运行结果是符合预期的。

程序是真的出了问题,而且我们可以运行几次,结果几乎不可能是100:

怎么解决呢?

在 一章中,虽然我们已经给出解决方案了,但是,这次我们使用AtomicInteger类来解决此类问题,而且用AtomicInteger类来解决此类问题最为合适。

改写例子,在Counter类中,用AtomicInteger类代替int:

然后, 获取value的方法内部需要改为“value.get();”

接着, 递增value的方法内部需要改为“value.incrementAndGet();”,至于incrementAndGet方法是什么意思,我们待会再说

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。我们程序运行了两遍,结果都为100,程序已经没有问题了。

至此,计数器的问题就先告一段落了。

下面就开始说说AtomicInteger类里面几个常用方法及源码。

4.返回get()/设置set​(int newValue)当前值方法

先来看看AtomicInteger类这两个方法:

  • get()
  • set​(int newValue)

下面依次来看看这两个方法。

get()方法在AtomicInteger类中的源码:

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

set​(int newValue)方法在AtomicInteger类中的源码:

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

接下来,我们来试试get()方法和set​(int newValue)方法。

新例子,不是上一小节的例子。

首先,创建出AtomicInteger对象并指定初始值:

然后,调用value的get()方法获取当前值:

接着,调用value的set​(int newValue)方法指定新值:

最后,调用value的get()方法再次获取当前值,看新值是否被设置成功:

例子书写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。值从0变化为1。

5.递增方法

AtomicInteger类中有两个递增方法:

  • getAndIncrement()
  • incrementAndGet()

其中, getAndIncrement()方法相当于i++,incrementAndGet()方法相当于++i。

我们来依次看看这两个方法。

getAndIncrement()方法在AtomicInteger类中的源码:

getAndIncrement()方法的作用是先返回当前值再递增。

incrementAndGet()方法在AtomicInteger类中的源码:

incrementAndGet()方法的作用是先递增再返回当前值。

接下来,我们来试试getAndIncrement()方法和incrementAndGet()方法。

新例子,不是上一小节的例子。

首先,我们创建一个对象并指定初始值:

然后,调用getAndIncrement()方法:

最后,调用incrementAndGet()方法:

例子书写完毕。

运行程序,执行结果:

静图:

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

首先调用getAndIncrement()方法时,value的值为0,跟据getAndIncrement()方法的先返回当前值再递增的原则,第一次输出结果正确;

getAndIncrement()方法递增完之后,value的值为1;

接下来,调用incrementAndGet()方法时,value值为1,根据incrementAndGet()方法的先递增再返回当前值的原则,第二次输出结果也正确;

incrementAndGet()方法先递增的结果就是:1被递增之后变为2。

说完AtomicInteger类中的递增方法,再来说说AtomicInteger类中的递减方法。

6.递减方法

AtomicInteger类中有两个递减方法:

  • getAndDecrement()
  • decrementAndGet()

其中, getAndDecrement()方法相当于i–,decrementAndGet()方法相当于–i。

我们来依次看看这两个方法。

getAndDecrement()方法在AtomicInteger类中的源码:

getAndDecrement()方法的作用是先返回当前值再递减。

decrementAndGet()方法在AtomicInteger类中的源码:

decrementAndGet()方法的作用是先递减再返回当前值。

接下来,我们来试试getAndDecrement()方法和decrementAndGet()方法。

新例子,不是上一小节的例子。

首先,我们创建一个对象并指定初始值:

然后,调用getAndDecrement()方法:

最后,调用decrementAndGet()方法:

例子书写完毕。

运行程序,执行结果:

静图:

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

首先调用getAndDecrement()方法时,value的值为0,跟据getAndDecrement()方法的先返回当前值再递减的原则,第一次输出结果正确;

getAndDecrement()方法递减完之后,value的值为-1;

接下来,调用decrementAndGet()方法时,value值为-1,根据decrementAndGet()方法的先递减再返回当前值的原则,第二次输出结果也正确;

decrementAndGet()方法先递减的结果就是:-1被递减之后结果为-2。

7.加上任意值方法

前面两小节演示的是自增和自减情况, 如果想要加上任意数,比如+5,或者你想要减去任意数,比如-5,使用前面那几个方法是做不到的,所以AtomicInteger类也为我们提供相应方法。

AtomicInteger类中有两个加上任意值的方法:

  • getAndAdd(int delta)
  • addAndGet(int delta)

如果你是做加法,那么就直接写一个正数即可;如果你是想做减法,那么就直接写一个负数即可。

我们来依次看看这两个方法。

getAndAdd(int delta)方法在AtomicInteger类中的源码:

getAndAdd(int delta)方法的作用是先返回当前值再加上任意值。

addAndGet(int delta)方法在AtomicInteger类中的源码:

addAndGet(int delta)方法的作用是先加上任意值再返回当前值。

接下来,我们来试试getAndAdd(int delta)方法和addAndGet(int delta)方法。

新例子,不是上一小节的例子。

首先,我们创建一个对象并指定初始值:

然后,调用getAndAdd(int delta)方法:

最后,调用addAndGet(int delta)方法:

例子书写完毕。

运行程序,执行结果:

静图:

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

首先调用getAndAdd(int delta)方法时,value的值为0,跟据getAndAdd(int delta)方法的先返回当前值再加上任意值的原则,第一次输出结果正确;

getAndAdd(int delta)方法加完任意值之后,value的值为3;

接下来,调用addAndGet(int delta)方法时,value值为3,根据addAndGet(int delta)方法的先加上任意值再返回当前值的原则,第二次输出结果也正确;

addAndGet(int delta)方法先加上任意值的结果就是:3加上-1结果为2。

8.自定义更新方式

前面几个小节演示的都是和指定数的加法或减法,如果我想自定义更新value的值怎么办呢?

AtomicInteger类为我们提供了两个可以自定义更新value值的方法:

  • getAndUpdate(IntUnaryOperator updateFunction)
  • updateAndGet(IntUnaryOperator updateFunction)

怎么更新呢?

你只需传入IntUnaryOperator接口的实现即可。

我们先来看看IntUnaryOperator接口:

IntUnaryOperator接口里面我们只需实现applyAsInt(int operand)方法即可

applyAsInt(int operand)方法中的值是我们调用getAndUpdate(IntUnaryOperator updateFunction)方法或updateAndGet(IntUnaryOperator updateFunction)方法时传递过去的

下面,我们来依次看看这两个方法。

getAndUpdate(IntUnaryOperator updateFunction)方法在AtomicInteger类中的源码:

getAndUpdate(IntUnaryOperator updateFunction)方法的作用是先返回当前值再更新为指定值。

updateAndGet(IntUnaryOperator updateFunction)方法在AtomicInteger类中的源码:

updateAndGet(IntUnaryOperator updateFunction)方法的作用是先更新为指定值再返回当前值。

接下来,我们来试试getAndUpdate(IntUnaryOperator updateFunction)方法和updateAndGet(IntUnaryOperator updateFunction)方法。

新例子,不是上一小节的例子。

首先,我们创建一个对象并指定初始值:

然后,调用getAndUpdate(IntUnaryOperator updateFunction)方法:

最后,调用updateAndGet(IntUnaryOperator updateFunction)方法:

例子书写完毕。

运行程序,执行结果:

静图:

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

首先调用getAndUpdate(IntUnaryOperator updateFunction)方法时,value的值为0,跟据getAndUpdate(IntUnaryOperator updateFunction)方法的先返回当前值再更新为指定值的原则,第一次输出结果正确;

getAndUpdate(IntUnaryOperator updateFunction)方法更新为指定值之后,value的值为1;

接下来,调用updateAndGet(IntUnaryOperator updateFunction)方法时,value值为1,根据updateAndGet(IntUnaryOperator updateFunction)方法的先更新为指定值再返回当前值的原则,第二次输出结果也正确;

updateAndGet(IntUnaryOperator updateFunction)方法先更新为指定值的结果就是:1+1之后结果为2。

9.CAS算法体现

我们之前在 一章中学习过什么是CAS算法。

在AtomicInteger类中也有体现:

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

下面我们来试试compareAndSet(int expectedValue, int newValue)方法。

新例子,不是上一小节的例子。

首先,我们创建一个对象并指定初始值:

然后,在调用compareAndSet(int expectedValue, int newValue)方法之前获取一次value的值:

接着,调用compareAndSet(int expectedValue, int newValue)方法:

最后,我们再获取一次value的值看发生变化没有:

例子改写完毕。

运行程序,执行结果:

静图:

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

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

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

祝大家编码愉快!

GitHub

本章程序GitHub地址:

总结

  • AtomicInteger是一个以原子方式操作int值的类。
  • get()方法的作用是获取AtomicInteger对象的当前值;
  • set​(int newValue)方法的作用是设置AtomicInteger对象的当前值。参数newValue是我们可以指定的新值。
  • getAndIncrement()方法的作用是先返回当前值再递增。
  • incrementAndGet()方法的作用是先递增再返回当前值。
  • getAndDecrement()方法的作用是先返回当前值再递减。
  • decrementAndGet()方法的作用是先递减再返回当前值。
  • getAndAdd(int delta)方法的作用是先返回当前值再加上任意值。
  • addAndGet(int delta)方法的作用是先加上任意值再返回当前值。
  • getAndUpdate(IntUnaryOperator updateFunction)方法的作用是先返回当前值再更新为指定值。
  • updateAndGet(IntUnaryOperator updateFunction)方法的作用是先更新为指定值再返回当前值。
  • compareAndSet(int expectedValue, int newValue)方法的作用是如果当value==expectedValue,那么就将newValue赋给value,否则什么也不做。

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

答疑

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

上一章

下一章

“全栈2019”Java原子操作第六章:AtomicInteger灵活的运算方式

学习小组

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

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。

全栈工程师学习计划

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

版权声明

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

文章来源:智云一二三科技

文章标题:“全栈2019”Java原子操作第五章:AtomicInteger介绍与使用

文章地址:https://www.zhihuclub.com/194224.shtml

关于作者: 智云科技

热门文章

网站地图