• AtomicInteger源码解析


    此文已由作者赵计刚授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    1、原子类

    • 可以实现一些原子操作

    • 基于CAS

    下面就以AtomicInteger为例。

     

    2、AtomicInteger

    在没有AtomicInteger之前,对于一个Integer的线程安全操作,是需要使用同步锁来实现的,当然现在也可以通过ReentrantLock来实现,但是最好最方便的实现方式是采用AtomicInteger。

    具体示例:

    package com.collection.test;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * 原子类的测试
     */
    public class AtomicTest {
        private static AtomicInteger atomicInteger = new AtomicInteger();
        
        //获取当前值
        public static void getCurrentValue(){
            System.out.println(atomicInteger.get());//-->0
        }
        
        //设置value值
        public static void setValue(){
            atomicInteger.set(12);//直接用12覆盖旧值
            System.out.println(atomicInteger.get());//-->12
        }
        
        //根据方法名称getAndSet就知道先get,则最后返回的就是旧值,如果get在后,就是返回新值
        public static void getAndSet(){
            System.out.println(atomicInteger.getAndSet(15));//-->12
        }
        
        public static void getAndIncrement(){
            System.out.println(atomicInteger.getAndIncrement());//-->15
        }
        
        public static void getAndDecrement(){
            System.out.println(atomicInteger.getAndDecrement());//-->16
        }
        
        public static void getAndAdd(){
            System.out.println(atomicInteger.getAndAdd(10));//-->15
        }
        
        public static void incrementAndGet(){
            System.out.println(atomicInteger.incrementAndGet());//-->26
        }
        
        public static void decrementAndGet(){
            System.out.println(atomicInteger.decrementAndGet());//-->25
        }
        
        public static void addAndGet(){
            System.out.println(atomicInteger.addAndGet(20));//-->45
        }
        
        public static void main(String[] args) {
            AtomicTest test = new AtomicTest();
            test.getCurrentValue();
            test.setValue();
            //返回旧值系列
            test.getAndSet();
            test.getAndIncrement();
            test.getAndDecrement();
            test.getAndAdd();
            //返回新值系列
            test.incrementAndGet();
            test.decrementAndGet();
            test.addAndGet();
            
        }
    }

    源代码:

        private volatile int value;// 初始化值
    
        /**
         * 创建一个AtomicInteger,初始值value为initialValue
         */
        public AtomicInteger(int initialValue) {
            value = initialValue;
        }
    
        /**
         * 创建一个AtomicInteger,初始值value为0
         */
        public AtomicInteger() {
        }
    
        /**
         * 返回value
         */
        public final int get() {
            return value;
        }
    
        /**
         * 为value设值(基于value),而其他操作是基于旧值<--get()
         */
        public final void set(int newValue) {
            value = newValue;
        }
    
        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
        
        /**
         * 基于CAS为旧值设定新值,采用无限循环,直到设置成功为止
         * 
         * @return 返回旧值
         */
        public final int getAndSet(int newValue) {
            for (;;) {
                int current = get();// 获取当前值(旧值)
                if (compareAndSet(current, newValue))// CAS新值替代旧值
                    return current;// 返回旧值
            }
        }
    
        /**
         * 当前值+1,采用无限循环,直到+1成功为止
         * @return the previous value 返回旧值
         */
        public final int getAndIncrement() {
            for (;;) {
                int current = get();//获取当前值
                int next = current + 1;//当前值+1
                if (compareAndSet(current, next))//基于CAS赋值
                    return current;
            }
        }
    
        /**
         * 当前值-1,采用无限循环,直到-1成功为止 
         * @return the previous value 返回旧值
         */
        public final int getAndDecrement() {
            for (;;) {
                int current = get();
                int next = current - 1;
                if (compareAndSet(current, next))
                    return current;
            }
        }
    
        /**
         * 当前值+delta,采用无限循环,直到+delta成功为止 
         * @return the previous value  返回旧值
         */
        public final int getAndAdd(int delta) {
            for (;;) {
                int current = get();
                int next = current + delta;
                if (compareAndSet(current, next))
                    return current;
            }
        }
    
        /**
         * 当前值+1, 采用无限循环,直到+1成功为止
         * @return the updated value 返回新值
         */
        public final int incrementAndGet() {
            for (;;) {
                int current = get();
                int next = current + 1;
                if (compareAndSet(current, next))
                    return next;//返回新值
            }
        }
    
        /**
         * 当前值-1, 采用无限循环,直到-1成功为止 
         * @return the updated value 返回新值
         */
        public final int decrementAndGet() {
            for (;;) {
                int current = get();
                int next = current - 1;
                if (compareAndSet(current, next))
                    return next;//返回新值
            }
        }
    
        /**
         * 当前值+delta,采用无限循环,直到+delta成功为止  
         * @return the updated value 返回新值
         */
        public final int addAndGet(int delta) {
            for (;;) {
                int current = get();
                int next = current + delta;
                if (compareAndSet(current, next))
                    return next;//返回新值
            }
        }
    
        /**
         * 获取当前值
         */
        public int intValue() {
            return get();
        }

    说明:使用与源代码都简单到爆了!自己看看注释。

    注意:

    • value是volatile的,关于volatile的相关内容见《附2 volatile》,具体链接:http://www.cnblogs.com/java-zhao/p/5125698.html

    • 单步操作:例如set()是直接对value进行操作的,不需要CAS,因为单步操作就是原子操作。

    • 多步操作:例如getAndSet(int newValue)是两步操作-->先获取值,在设置值,所以需要原子化,这里采用CAS实现。

    • 对于方法是返回旧值还是新值,直接看方法是以get开头(返回旧值)还是get结尾(返回新值)就好

    • CAS:比较CPU内存上的值是不是当前值current,如果是就换成新值update,如果不是,说明获取值之后到设置值之前,该值已经被别人先一步设置过了,此时如果自己再设置值的话,需要在别人修改后的值的基础上去操作,否则就会覆盖别人的修改,所以这个时候会直接返回false,再进行无限循环,重新获取当前值,然后再基于CAS进行加减操作。

    • 如果还是不懂CAS,类比数据库的乐观锁

    补充一个东西:

     1     // setup to use Unsafe.compareAndSwapInt for updates
     2     private static final Unsafe unsafe = Unsafe.getUnsafe();
     3     private static final long valueOffset;
     4 
     5     static {
     6         try {
     7             valueOffset = unsafe.objectFieldOffset
     8                 (AtomicInteger.class.getDeclaredField("value"));
     9         } catch (Exception ex) { throw new Error(ex); }
    10     }
    11 
    12     private volatile int value;

    这是AtomicInteger的所有属性,其中value存的是当前值,而当前值存放的内存地址可以通过valueOffset来确定。实际上是“value字段相对Java对象的起始地址的偏移量”

    1     public final boolean compareAndSet(int expect, int update) {
    2         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    3     }

    CAS方法:通过对比“valueOffset上的value”与expect是否相同,来决定是否修改value值为update值。


    免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

    更多网易技术、产品、运营经验分享请点击


    相关文章:
    【推荐】 Android中Textview显示Html,图文混排,支持图片点击放大
    【推荐】 结合jenkins以及PTP平台的性能回归测试
    【推荐】 视觉设计师的进化

  • 相关阅读:
    java 获取未知枚举的集合(get unknown enum list)
    解析Disruptor:写入ring buffer
    解析Disruptor:拼接依赖
    Python3.x在linux下print中文问题
    Python3源码方式编译
    正则表达式学习
    PHP传值和传引用、传地址的区别
    php中关于sizeof()函数
    [原]JointJS流程图
    [原]OpeanLayers3 For ArcGIS MapServer
  • 原文地址:https://www.cnblogs.com/163yun/p/10137257.html
Copyright © 2020-2023  润新知