Java中的原子类AtomicInteger使用详解

 更新时间:2023年12月08日 10:06:24   作者:努力的小强  
这篇文章主要介绍了Java中的原子类AtomicInteger使用详解,原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换,需要的朋友可以参考下

原子操作

原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。

原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分,将整个操作视作一个整体是原子性的核心特征。

原子类

在Java中提供了很多原子类,主要把这些原子类分成以下几大类

在这里插入图片描述

原子更新基本类型或引用类型

  • AtomicBoolean
    • 原子更新布尔类型,内部使用int类型的value存储1和0表示true和false,底层也是对int类型的原子操作。
  • AtomicInteger
    • 原子更新int类型。
  • AtomicLong
    • 原子更新long类型。
  • AtomicReference
    • 原子更新引用类型,通过泛型指定要操作的类。
  • AtomicMarkableReference
    • 原子更新引用类型,内部使用Pair承载引用对象及是否被更新过的标记,避免了ABA问题。
  • AtomicStampedReference
    • 原子更新引用类型,内部使用Pair承载引用对象及更新的邮戳,避免了ABA问题。

原子更新数组中的元素

原子更新数组中的元素,可以更新数组中指定索引位置的元素。

  • AtomicIntegerArray
    原子更新int数组中的元素。
  • AtomicLongArray
    原子更新long数组中的元素。
  • AtomicReferenceArray
    原子更新object数组中的元素。

原子更新对象中的字段

原子更新对象中的字段,可以更新对象中指定字段名称的字段。

  • AtomicIntegerFieldUpdater
    原子更新对象中的int类型字段。
  • AtomicLongFieldUpdater
    原子更新对象中的long类型字段。
  • AtomicReferenceFieldUpdater
    原子更新对象中的引用类型字段。

高性能原子类

高性能原子类,是Java8中增加的原子类,它们使用分段的思想,把不同线程hash到不同的段上去更新,最后再把这些段的值相加得到最终的值。

Striped64
下面四个类的父类。

  • LongAccumulator
    • long类型的聚合器,需要传入一个long类型的二元操作,可以用来计算各种聚合操作,包括加乘等。
  • LongAdder
    • long类型聚合器,LongAccumulator的特例,只能用来计算加法,且从零开始计算。
  • DoubleAccumulator
    • double类型的聚合器,需要传入一个double类型的二元操作,可以用来计算各种聚合操作,包括加乘等。
  • DoubleAdder
    • double类型聚合器,DoubleAccumulator的特例,只能用来计算加法,且从零开始计算。

AtomicInteger使用

import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerDemo {
    public static void main(String[] args) throws InterruptedException {
        test1();
        test2();
    }
    private static void test1() throws InterruptedException {
        Counter counter = new Counter();
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    counter.addCount();
                }
            }).start();
        }
        Thread.sleep(1000);
        System.out.println("test1 count = " + counter.getCount());
    }
    private static void test2() throws InterruptedException {
        AtomicInteger count = new AtomicInteger();
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    count.incrementAndGet();
                }
            }).start();
        }
        Thread.sleep(1000);
        System.out.println("test2 count = " + count.get());
    }
}
public class Counter {
    private volatile static int count = 0;
    public void addCount(){
        count++;
    }
    public int getCount(){
        return count;
    }
}

运行以上代码会发现,test1的结果达不到预期的10000,而且每次的结果不可再现。而test2的结果每次都是10000,是确定的可再现的。

是因为test1中调用的Counter类的addCount方法,这个方法不是原子性的。

count++可以分解为以下几个原子性的步骤:

1.读取count的值

2.计算新值count+1

3.新值写入count变量

如果步骤1、2、3中有多个线程并发执行,那么就会出现两个或多个线程并发的执行+1操作,而我们希望的是每个线程依次执行+1的操作。

AtomicInteger原理

AtomicInteger声明

public class AtomicInteger extends Number implements java.io.Serializable

Unsafe类的使用

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

AtomicInteger属性

private volatile int value;

AtomicInteger构造器

    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
    public AtomicInteger() {
    }

AtomicInteger自增

    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

调用Unsafe类的方法

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

compareAndSwapInt即CAS方式修改int值:

  1. 调用unsafe.getAndAddInt方法。
  2. unsafe.getAndAddInt方法通过自旋的方式,每次尝试通过CAS方式对原值进行累加。如果累加失败,将进入下一次循环。如果累加成功,则自选结束。

到此这篇关于Java中的原子类AtomicInteger使用详解的文章就介绍到这了,更多相关Java原子类AtomicInteger内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈Java8对字符串连接的改进正确姿势

    浅谈Java8对字符串连接的改进正确姿势

    这篇文章主要介绍了Java8:对字符串连接的改进,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • Mybatis内置参数之_parameter和_databaseId的使用

    Mybatis内置参数之_parameter和_databaseId的使用

    这篇文章主要介绍了Mybatis内置参数之_parameter和_databaseId的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • SpringAOP 构造注入的实现步骤

    SpringAOP 构造注入的实现步骤

    这篇文章主要介绍了SpringAOP_构造注入的实现步骤,帮助大家更好的理解和学习使用spring框架,感兴趣的朋友可以了解下
    2021-05-05
  • springboot集成redis实现简单秒杀系统

    springboot集成redis实现简单秒杀系统

    这篇文章主要为大家详细介绍了springboot集成redis实现简单秒杀系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • Java使用Mail构建邮件功能的完整指南

    Java使用Mail构建邮件功能的完整指南

    Java Mail API 是一个功能强大的工具,它可以帮助开发者轻松实现邮件的发送与接收功能,本文将介绍如何使用 Java Mail 发送和接收邮件,希望对大家有所帮助
    2025-03-03
  • 使用java连接Redis,Maven管理操作

    使用java连接Redis,Maven管理操作

    这篇文章主要介绍了使用java连接Redis,Maven管理操作,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • 聊聊Spring Cloud Cli 初体验

    聊聊Spring Cloud Cli 初体验

    这篇文章主要介绍了聊聊Spring Cloud Cli 初体验,SpringBoot CLI 是spring Boot项目的脚手架工具。非常具有实用价值,需要的朋友可以参考下
    2018-04-04
  • Java中Arrays.sort自定义一维数组、二维数组的排序方式

    Java中Arrays.sort自定义一维数组、二维数组的排序方式

    这篇文章主要介绍了Java中Arrays.sort自定义一维数组、二维数组的排序方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 浅谈JAVA内存分配与参数传递

    浅谈JAVA内存分配与参数传递

    这篇文章主要介绍了JAVA内存分配与参数传递,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • Java验证时间格式是否正确方法类项目实战

    Java验证时间格式是否正确方法类项目实战

    在很多场景中我们需要验证时间日期的是否属于正确的格式,验证时间是否符合常规的,本文就来介绍一下几种方式,感兴趣的可以了解一下
    2022-04-04

最新评论