java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java原子类AtomicInteger

Java中的原子类AtomicInteger使用详解

作者:努力的小强

这篇文章主要介绍了Java中的原子类AtomicInteger使用详解,原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换,需要的朋友可以参考下

原子操作

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

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

原子类

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

在这里插入图片描述

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

原子更新数组中的元素

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

原子更新对象中的字段

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

高性能原子类

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

Striped64
下面四个类的父类。

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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文