一、AtomicInteger简介

AtomicInteger,应该是atomic框架中用得最多的原子类了。顾名思义,AtomicInteger是Integer类型的线程安全原子类,可以在应用程序中以原子的方式更新int值。

1. 创建AtomicInteger对象

先来看下AtomicInteger对象的创建。

AtomicInteger提供了两个构造器,使用默认构造器时,内部int类型的value值为0:

AtomicInteger atomicInt = new AtomicInteger();

AtomicInteger类的内部并不复杂,所有的操作都针对内部的int值——value,并通过Unsafe类来实现线程安全的CAS操作:

2. AtomicInteger的使用

来看下面这个示例程序:

public class Main {

public static void main(String[] args) throws InterruptedException {

AtomicInteger ai = new AtomicInteger();

List list = new ArrayList<>();

for (int i = 0; i < 10; i++) {

Thread t = new Thread(new Accumlator(ai), "thread-" + i);

list.add(t);

t.start();

}

for (Thread t : list) {

t.join();

}

System.out.println(ai.get());

}

static class Accumlator implements Runnable {

private AtomicInteger ai;

Accumlator(AtomicInteger ai) {

this.ai = ai;

}

@Override

public void run() {

for (int i = 0, len = 1000; i < len; i++) {

ai.incrementAndGet();

}

}

}

}

上述代码使用了AtomicInteger的incrementAndGet方法,以原子的操作对int值进行自增,该段程序执行的最终结果为10000(10个线程,每个线程对AtomicInteger增加1000),如果不使用AtomicInteger,使用原始的int或Integer,最终结果值可能会小于10000(并发时读到了过时的数据或存在值覆盖的问题)。

我们来看下incrementAndGet内部:

内部调用了Unsafe类的getAndAddInt方法,以原子方式将value值增加1,然后返回增加前的原始值。

注意,上述是JDK1.8的实现,在JDK1.8之前,上述方法采用了自旋+CAS操作的方式:

public final int getAndIncrement() {

for (;;) {

int current = get();

int next = current + 1;

if (compareAndSet(current, next))

return current;

}

}

3. AtomicInteger的特殊方法说明

AtomicInteger中有一个比较特殊的方法——lazySet:

lazySet方法是set方法的不可见版本。什么意思呢?

我们知道通过volatile修饰的变量,可以保证在多处理器环境下的“可见性”。也就是说当一个线程修改一个共享变量时,其它线程能立即读到这个修改的值。volatile的实现最终是加了内存屏障:

保证写volatile变量会强制把CPU写缓存区的数据刷新到内存

读volatile变量时,使缓存失效,强制从内存中读取最新的值

由于内存屏障的存在,volatile变量还能阻止重排序

lazySet内部调用了Unsafe类的putOrderedInt方法,通过该方法对共享变量值的改变,不一定能被其他线程立即看到。也就是说以普通变量的操作方式来写变量。

为什么会有这种奇怪方法?什么情况下需要使用lazySet呢?

考虑下面这样一个场景:

private AtomicInteger ai = new AtomicInteger();

lock.lock();

try

{

// ai.set(1);

}

finally

{

lock.unlock();

}

由于锁的存在:

lock()方法获取锁时,和volatile变量的读操作一样,会强制使CPU缓存失效,强制从内存读取变量。

unlock()方法释放锁时,和volatile变量的写操作一样,会强制刷新CPU写缓冲区,把缓存数据写到主内存

所以,上述ai.set(1)可以用ai.lazySet(1)方法替换:

由锁来保证共享变量的可见性,以设置普通变量的方式来修改共享变量,减少不必要的内存屏障,从而提高程序执行的效率。

二、类/接口说明

类声明

构造器

接口声明

方法声明

描述

int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction)

使用IntBinaryOperator 对当前值和x进行计算,并更新当前值,返回计算后的新值

int addAndGet(int delta)

以原子方式将给定值与当前值相加,返回相加后的新值

boolean compareAndSet(int expect, int update)

如果当前值 == expect,则以原子方式将该值设置为给定的更新值(update)

int decrementAndGet()

以原子方式将当前值减 1,返回新值

int get()

获取当前值

int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction)

使用IntBinaryOperator 对当前值和x进行计算,并更新当前值,返回计算前的旧值

int getAndAdd(int delta)

以原子方式将给定值与当前值相加,返回旧值

int getAndDecrement()

以原子方式将当前值减 1,返回旧值

int getAndIncrement()

以原子方式将当前值加 1,返回旧值

int getAndSet(int newValue)

以原子方式设置为给定值,并返回旧值

int getAndUpdate(IntUnaryOperator updateFunction)

使用IntBinaryOperator 对当前值进行计算,并更新当前值,返回计算前的旧值

int incrementAndGet()

以原子方式将当前值加 1,返回新值

void lazySet(int newValue)

设置为给定值,但不保证值的改变被其他线程立即看到

void set(int newValue)

设置为给定值

int updateAndGet(IntUnaryOperator updateFunction)

使用IntBinaryOperator 对当前值进行计算,并更新当前值,返回计算后的新值

boolean weakCompareAndSet(int expect, int update)

weakCompareAndSet无法保证除操作目标外的其他变量的执行顺序( 编译器和处理器为了优化程序性能而对指令序列进行重新排序 ),同时也无法保证这些变量的可见性。

三、其它原子类

与AtomicInteger类似的原子类还有AtomicBoolean和AtomicLong,底层都是通过Unsafe类做CAS操作,来原子的更新状态值。可以参考Oracle官方文档:https://docs.oracle.com/javas...,不再赘述。

java atomicinteger_Java多线程进阶(十三)—— J.U.C之atomic框架:AtomicInteger相关推荐

  1. java blockingqueue_Java多线程进阶(三一)—— J.U.C之collections框架:BlockingQueue接口...

    一.引言 从本节开始,我们将介绍juc-collections框架中的"阻塞队列"部分.阻塞队列在实际应用中非常广泛,许多消息中间件中定义的队列,通常就是一种"阻塞队列& ...

  2. Java多线程进阶(一)—— J.U.C并发包概述

    本文首发于一世流云专栏: https://segmentfault.com/blog... J.U.C包简介 J.U.C并发包,即java.util.concurrent包,是JDK的核心工具包,是J ...

  3. Java多线程系列之J.U.C并发包概述

    J.U.C包简介 J.U.C并发包,即java.util.concurrent包,是JDK的核心工具包,是JDK1.5之后,由 Doug Lea实现并引入. 整个java.util.concurren ...

  4. 【Java程序设计】多线程进阶

    多线程进阶 文章目录 多线程进阶 一.线程之间的通信 二.死锁 (1)死锁相关概念 (2)死锁的例子 三.后台(守护)线程 四.线程的生命周期 五.线程的优先级 (1)优先级 (2)基于线程优先级的线 ...

  5. Java多线程进阶面试-Atomic 原子类

    1.介绍一下 Atomic 原子类 Atomic 翻译成中文是原子的意思.在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的.在我们这里 Atomic 是指一个操作是不可中断的. ...

  6. 201521123122 《java程序设计》第十三周学习总结

    ## 201521123122 <java程序设计>第十三周实验总结 ## 1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1 ...

  7. 操作系统--多线程进阶(上)

    目录 前言 一丶常见的锁策略 <1>乐观锁和悲观锁思想 1>乐观锁 2>悲观锁 <2>重量级锁和轻量级锁 1>重量级锁 关于用户态切换到内核态的方式 2> ...

  8. JUC并发多线程进阶

    笔记整理来源 B站UP主狂神说Java https://space.bilibili.com/95256449/ JUC并发多线程进阶 1.什么是JUC 源码+官方文档 JUC是 java util ...

  9. 【学习笔记】多线程进阶JUC

    JUC多线程进阶 1.什么是JUC 源码 + 官方文档 JUC是 java util concurrent 业务:普通的线程代码 Thread Runnable: 没有返回值.效率相比于Callabl ...

最新文章

  1. 通过 .htaccess 实现缓存策略
  2. python语法学习_Python学习1——语法
  3. 一个黑色全屏的计时器_我入手了一个1000多的智能手环,值吗?|Fitbit Charge 4测评...
  4. mysql 字符串取前缀_mysql截取字符串的函数总结
  5. 根据概率分布随机采样python_PR Sampling Ⅱ:马尔可夫链蒙特卡洛 MCMC及python实现...
  6. Java实现一个字符串的反转
  7. 字符编码原理 ASCII,Unicode和UTF-8 - - ITeye技术网站
  8. SQL大全------之 oracle关于insert all的用法
  9. Practical Lessons from Predicting Clicks on Ads at Facebook
  10. 【Android 逆向】加壳技术识别 ( VMP 加壳示例 | Dex2C 加壳示例 )
  11. 大学高数常微分方程思维导图_思维导图_2016考研数学:高数中六种常见题型归纳_沪江英语...
  12. windows 7 静默 安装 软件
  13. 谁在叩响野蛮人的家门?
  14. 【原创】将RGB图像转换到CMY空间
  15. 为什么安卓手机没有苹果手机流畅?
  16. 两款网页在线刷网站访客pv和ip的源码
  17. python写文件numpy_Numpy | 23 文件读写
  18. python中的os.listdir()方法、os.path.isdir()方法
  19. 系统分析师论文5:论软件的系统测试及其应用
  20. 着色器Encoding floats to RGBA

热门文章

  1. 5.6 date:显示与设置系统时间
  2. mysql 创建用户权限_10.创建 MySQL 用户及赋予用户权限
  3. 几种排序算法性能的比较
  4. 如何将业务系统的数据抽取汇聚到数据中台?
  5. 云原生演进趋势下传统数据库升级实践
  6. AI体验馆上线!集成业界领先NLP场景深度迁移学习框架EasyTransfer
  7. 面向云数据库,超低延迟文件系统PolarFS诞生了
  8. UI设计:浅议内滚动布局
  9. CF双端总决赛还是LGD总决赛?端游战队挺进决赛,手游已拿三连冠
  10. ASP.NET Core微服务(七)——【docker部署linux上线】(RDS+API接口测试部分)