zoukankan      html  css  js  c++  java
  • 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平台的性能回归测试
    【推荐】 视觉设计师的进化

  • 相关阅读:
    关于求 p_i != i and p_i != i+1 的方案数的思考过程
    poj 3041 Asteroids 二分图最小覆盖点
    poj 1325 Machine Schedule 最小顶点覆盖
    poj 1011 Sticks 减枝搜索
    poj 1469 COURSES 最大匹配
    zoj 1516 Uncle Tom's Inherited Land 最大独立边集合(最大匹配)
    Path Cover (路径覆盖)
    hdu 3530 SubSequence TwoPoint单调队列维护最值
    zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)
    poj 1466 Girls and Boys 二分图最大独立子集
  • 原文地址:https://www.cnblogs.com/163yun/p/10137257.html
Copyright © 2011-2022 走看看