(十二)J.U.C之atomic框架:AtomicInteger

℡╲_俬逩灬. 提交于 2020-03-17 11:55:12

一、简介

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

 

1.创建

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<Thread> 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,如果不使用AtomicInteger,使用原始的int或Integer,最终结果值可能会小于10000(并发时读到了过时的数据或存在值覆盖的问题)。

 

我们来看下incrementAndGet内部:

 

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

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

 

 

3.AtomicInteger的特殊方法说明

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

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

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

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

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

 

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

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

考虑下面这样一个场景:

 

由于锁的存在:

  • lock()方法获取锁时,和volatile变量的读操作一样,会强制使CPU缓存失效,强制从内存读取变量。
  • unlock()方法释放锁时,和volatile变量的写操作一样,会强制刷新CPU写缓冲区,把缓存数据写到主内存

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

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

 

 

 

二、类/接口说明

 

 

三、其它原子类

与AtomicInteger类似的原子类还有AtomicBoolean和AtomicLong,底层都是通过Unsafe类做CAS操作,来原子的更新状态值。

 

 

借鉴学习自https://segmentfault.com/a/1190000015825207

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!