文章目录

  • 一、什么是原子类
  • 二、原子类的底层实现
  • 三、常用的原子类
    • 3.1、AtomicInteger与AtomicLong
    • 3.2、LongAdder
  • 四、原子类的性能测试
    • 4.1、测试程序
    • 4.2、测试结果
    • 4.3、结果分析
    • 4.4、底层实现分析

一、什么是原子类

Java中提供了一些原子类,原子类包装了一个变量,并且提供了一系列对变量进行原子性操作的方法。我们在多线程环境下对这些原子类进行操作时,不需要加锁,大大简化了并发编程的开发。

二、原子类的底层实现

目前Java中提供的原子类大部分底层使用了CAS锁(CompareAndSet自旋锁),如AtomicInteger、AtomicLong等;也有使用了分段锁+CAS锁的原子类,如LongAdder等。

三、常用的原子类

3.1、AtomicInteger与AtomicLong

AtomicInteger与AtomicLong的底层实现与用法基本相同,不同点在于AtomicInteger包装了一个Integer型变量,而AtomicLong包装了一个Long型变量。
AtomicInteger与AtomicLong的底层实现都使用了CAS锁。

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;/*** @author IT00ZYQ* @date 2021/5/24 15:33**/
public class T13_AtomicInteger {private static AtomicInteger atomicInteger = new AtomicInteger();private static AtomicLong atomicLong = new AtomicLong();private static Integer integer = 0;private static Long lon = 0L;public static void main(String[] args) {// 创建10个线程,分别对atomicInteger、atomicLong、integer、lon进行1000次增加1的操作// 如果操作是原子性的,那么正确结果 = 10 * 1000 = 10000Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(() -> {for (int j = 1; j <= 1000; j++) {atomicInteger.incrementAndGet();atomicLong.incrementAndGet();integer ++;lon ++;}});}// 启动线程for (Thread thread : threads) {thread.start();}// 保证10个线程运行完成try {for (Thread thread : threads) {thread.join();}} catch (InterruptedException e) {e.printStackTrace();}System.out.println("AtomicInteger的结果:" + atomicInteger);System.out.println("AtomicLong的结果:" + atomicLong);System.out.println("Integer的结果:" + integer);System.out.println("Long的结果:" + lon);}
}

运行结果:

AtomicInteger的结果:10000
AtomicLong的结果:10000
Integer的结果:4880
Long的结果:4350Process finished with exit code 0

多次运行发现原子类AtomicInteger与AtomicLong每次都能得到正确的结果10000,但是非原子类Integer与Long一般情况下都达不到10000,每次的结果也可能不一样。

3.2、LongAdder

LongAdder的底层实现使用了分段锁,每个段使用的锁是CAS锁,所以LongAdder的底层实现是分段锁+CAS锁。
在上面的程序添加了一个LongAdder变量进行测试

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;/*** @author IT00ZYQ* @date 2021/5/24 15:33**/
public class T13_AtomicInteger {private static AtomicInteger atomicInteger = new AtomicInteger();private static AtomicLong atomicLong = new AtomicLong();private static LongAdder longAdder = new LongAdder();private static Integer integer = 0;private static Long lon = 0L;public static void main(String[] args) {// 创建10个线程,分别对atomicInteger、atomicLong、integer、lon进行1000次增加1的操作// 如果操作是原子性的,那么正确结果 = 10 * 1000 = 10000Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(() -> {for (int j = 1; j <= 1000; j++) {atomicInteger.incrementAndGet();atomicLong.incrementAndGet();integer ++;lon ++;longAdder.increment();}});}// 启动线程for (Thread thread : threads) {thread.start();}// 保证10个线程运行完成try {for (Thread thread : threads) {thread.join();}} catch (InterruptedException e) {e.printStackTrace();}System.out.println("AtomicInteger的结果:" + atomicInteger);System.out.println("AtomicLong的结果:" + atomicLong);System.out.println("Integer的结果:" + integer);System.out.println("Long的结果:" + lon);System.out.println("LongAdder的结果:" + longAdder);}
}

运行结果:

AtomicInteger的结果:10000
AtomicLong的结果:10000
Integer的结果:6871
Long的结果:6518
LongAdder的结果:10000Process finished with exit code 0

LongAdder类也是能够正确输出结果的。

四、原子类的性能测试

4.1、测试程序

package juc;import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;/*** @author IT00ZYQ* @date 2021/5/24 15:51**/
public class T14_AtomicClassPerformance {private static AtomicLong atomicLong = new AtomicLong();private static LongAdder longAdder = new LongAdder();/*** 线程数*/private static final int THREAD_COUNT = 100;/*** 每次线程循环操作次数*/private static final int OPERATION_COUNT = 10000;public static void main(String[] args) {Thread[] threads = new Thread[THREAD_COUNT];// 创建对AtomicLong进行操作的线程for (int i = 0; i < THREAD_COUNT; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < OPERATION_COUNT; j++) {atomicLong.incrementAndGet();}});}long start1 = System.currentTimeMillis();// 启动线程for (Thread thread : threads) {thread.start();}// 保证线程运行完成try {for (Thread thread : threads) {thread.join();}} catch (InterruptedException e) {e.printStackTrace();}long end1 = System.currentTimeMillis();// 创建对LongAdder进行操作的线程for (int i = 0; i < THREAD_COUNT; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < OPERATION_COUNT; j++) {longAdder.increment();}});}long start2 = System.currentTimeMillis();// 启动线程for (Thread thread : threads) {thread.start();}// 保证线程运行完成try {for (Thread thread : threads) {thread.join();}} catch (InterruptedException e) {e.printStackTrace();}long end2 = System.currentTimeMillis();System.out.println("AtomicLong运行时间: " + (end1 - start1) + "ms, 运行结果:" + atomicLong);System.out.println("LongAdder运行时间: " + (end2 - start2) + "ms, 运行结果:" + longAdder);}}

4.2、测试结果

THREAD_COUNT = 100, OPERATION_COUNT = 1000时的运行结果

AtomicLong运行时间: 40ms, 运行结果:100000
LongAdder运行时间: 57ms, 运行结果:100000Process finished with exit code 0

THREAD_COUNT = 100, OPERATION_COUNT = 10000时的运行结果

AtomicLong运行时间: 108ms, 运行结果:1000000
LongAdder运行时间: 85ms, 运行结果:1000000Process finished with exit code 0

THREAD_COUNT = 100, OPERATION_COUNT = 1000000时的运行结果

AtomicLong运行时间: 6909ms, 运行结果:100000000
LongAdder运行时间: 468ms, 运行结果:100000000Process finished with exit code 0

THREAD_COUNT = 10, OPERATION_COUNT = 1000000时的运行结果

AtomicLong运行时间: 788ms, 运行结果:10000000
LongAdder运行时间: 162ms, 运行结果:10000000Process finished with exit code 0

4.3、结果分析

THREAD_COUNT * OPERATION_COUN足够小时,AtomicInteger的性能会略高于LongAdder,而随着THREAD_COUNT * OPERATION_COUN的增加,LongAdder的性能更高,THREAD_COUNT * OPERATION_COUN足够大时,LongAdder的性能远高于AtomicInteger。

4.4、底层实现分析

  • AtomicLong的原子性自增操作,是通过CAS实现的。在竞争线程数较少且每个线程的运行所需时间较短的情况下,这样做是合适的。但是如果线程竞争激烈,会造成大量线程在原地打转、不停尝试去修改值,但是老是发现值被修改了,于是继续自旋。 这样浪费了大量的CPU资源。
  • LongAdder在竞争激烈时,多个线程并不会一直自旋来修改值,而是采用了分段的思想,各个线程会分散累加到自己所对应的Cell[]数组的某一个数组对象元素中,而不会大家共用一个,把不同线程对应到不同的Cell中进行修改,降低了对临界资源的竞争。本质上,是用空间换时间。

Java中常用的原子类相关推荐

  1. 【java中常用的API】

    java中有很多常用的API,它们提供了便捷的使用方法和工具类,让我们来看一看java中常用的API吧. 1.math类: 它包含基本的数字运算方法,如对数.指数.平方根和三角函数等,一般数据类型为d ...

  2. java 中常用的类

    java 中常用的类 Math Math 类,包含用于执行基本数学运算的方法 常用API 取整 l  static double abs(double  a) 获取double 的绝对值 l  sta ...

  3. Java多线程系列--“JUC原子类”01之 框架

    2019独角兽企业重金招聘Python工程师标准>>> Java多线程系列--"JUC原子类"01之 框架 根据修改的数据类型,可以将JUC包中的原子操作类可以分 ...

  4. 动图 + 源码,演示 Java 中常用数据结构执行过程及原理

    最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...

  5. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

  6. 数据结构中缀表达式转后缀表达式与后缀表达式的求值实训报告_动图+源码,演示 Java 中常用数据结构执行过程及原理...

    程序员的成长之路互联网/程序员/成长/职场 关注 阅读本文大概需要 3.7 分钟. 作者:大道方圆cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, ...

  7. JAVA中常用接口的介绍及使用示例 java lang Comparable

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! JAVA ...

  8. 注解以及Java中常用注解使用

    元注解有六个: @Target(表示该注解可以用于什么地方). @Retention(表示再什么级别保存该注解信息). @Documented(将此注解包含再javadoc中). @Inherited ...

  9. Java中常用的API

    文章目录 前言 一.java.lang String StringBuilder Integer parseXXX Math Object System Throwable Thread Runnab ...

最新文章

  1. 零基础入门学习Python(13)-字符串
  2. Spring Boot 基于注解驱动源码分析--自动配置
  3. 程序可以下载,在线调试disassembly窗口就出现了大片0x00000000 FFFFFFFF DCD 0xFFFFFFFF ; ? Undefined
  4. oracle错误 904,ORACLE 导出错误 EXP-00008: 遇到 Oracle 错误 904
  5. Linux C/C++多线程pthread实例
  6. 在中断程序里修改全局变量的童鞋注意啦~(C中的volatile作用 转载~)
  7. java jml_JML 入门
  8. 经典重温:CVPR 2010 What is an object?
  9. idea IDE 常用快捷键记录
  10. 快捷操作之争【原创】
  11. 前端和java选哪个_web前端和java哪个好?新手该选择哪个
  12. win10计算机磁盘图标,win10系统本地磁盘图标显示异常如何恢复
  13. python 简单 socket 编程
  14. windows cmd命令行添加mysql环境变量
  15. WARNING:tensorflow:sample_weight modes were coerced from ... to [‘...‘]
  16. 两个stanby的NameNode问题解决
  17. 【转】Sphinx速成指南
  18. 解决idea项目没有蓝色小方块
  19. 报错 Illegal instruction
  20. 【内网穿透服务器】使用FRP实现内网穿透,远程访问内网服务器

热门文章

  1. abb机器人指令手册_ABB机器人新示教器Touch Jog
  2. div 把四个角 变圆
  3. ssdp协议 upnp_SSDP,简单服务发现协议
  4. 一分钟教你学会手动提取pdx文件
  5. C 懒虫小鑫 SDUT
  6. Office办公软件介绍二
  7. tcp要点学习-建立连接断开连接
  8. ​【斯坦福出品】吴恩达CS230深度学习课小抄来了 | 附下载
  9. 阿里巴巴获得商品详情 API调用示例
  10. 七张图带你了解电子招标投标全流程!