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

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


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平台的性能回归测试
【推荐】 视觉设计师的进化

AtomicInteger源码解析的更多相关文章

  1. lesson8:AtomicInteger源码解析及性能分析

    AtomicInteger等对象出现的目的主要是为了解决在多线程环境下变量计数的问题,例如常用的i++,i--操作,它们不是线程安全的,AtomicInteger引入后,就不必在进行i++和i--操作 ...

  2. 第十一章 AtomicInteger源码解析

    1.原子类 可以实现一些原子操作 基于CAS 下面就以AtomicInteger为例. 2.AtomicInteger 在没有AtomicInteger之前,对于一个Integer的线程安全操作,是需 ...

  3. LinkedBlockingQueue源码解析(3)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 4.3.public E take() throws InterruptedException 原理: 将队 ...

  4. 第九章 LinkedBlockingQueue源码解析

    1.对于LinkedBlockingQueue需要掌握以下几点 创建 入队(添加元素) 出队(删除元素) 2.创建 Node节点内部类与LinkedBlockingQueue的一些属性 static ...

  5. 多线程爬坑之路-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

  6. [Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

  7. Android -- AsyncTask源码解析

    1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+ ...

  8. ThreadPoolExecutor系列<三、ThreadPoolExecutor 源码解析>

    本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7681826.html 在源码解析前,需要先理清线程池控制的运行状态 ...

  9. LinkedBlockingQueue源码解析

    上一篇博客,我们介绍了ArrayBlockQueue,知道了它是基于数组实现的有界阻塞队列,既然有基于数组实现的,那么一定有基于链表实现的队列了,没错,当然有,这就是我们今天的主角:LinkedBlo ...

随机推荐

  1. php中错误处理机制

    php中,异常处理机制是有限的,无法自动抛出异常,必须手动进行,并且内置异常有限. php把许多异常看作错误,这样就可以把这些异常想错误一样用set_error_handler接管,进而主动抛出异常. ...

  2. 【转】VS2012 中文版转英文版 英文版转中文版 界面语言切换

    [1]下载VS2012的语言包,各种语言包都有,下载对应的即可. 微软官网衔接地址:vs2012 语言包  http://www.microsoft.com/zh-CN/download/detail ...

  3. css简单分页

    html代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...

  4. 用Vue-cli生成vue+webpack的项目模板怎么设置为vue1.0版本?

    用Vue-cli生成vue+webpack的项目模板 $ npm install -g vue-cli $ vue init webpack my-project $ cd my-project $ ...

  5. Jmeter If Controller中设置多个条件用“与”进行连接

    "${noteID}"!="NOT FOUND" && "${securitiesId}"!="0P00011FQ ...

  6. c:param 标签后不要写 注释 。否则报错 Encountered illegal body of tag "c:import" tag, given its attributes

    c:param 标签后不要写 注释 .否则报错  Encountered illegal body of tag "c:import" tag, given its attribu ...

  7. 2018.06.27Going Home(二分图匹配)

    Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 24716 Accepted: 12383 Descript ...

  8. 2018.09.08 NOIP模拟 division(状压dp)

    这么sb的题考场居然写挂了2233. 假设n=∏iaiki" role="presentation" style="position: relative;&qu ...

  9. 2018.09.07 bzoj1096: [ZJOI2007]仓库建设(斜率优化dp)

    传送门 斜率优化dp经典题. 令f[i]表示i这个地方修建仓库的最优值,那么答案就是f[n]. 用dis[i]表示i到1的距离,sump[i]表示1~i所有工厂的p之和,sum[i]表示1~i所有工厂 ...

  10. spring cloud--------------------HystrixCommand使用

    一.注解使用: (一)注解同步执行 1.注解开启断路器功能 @EnableCircuitBreaker 2.方法事例 @HystrixCommand(fallbackMethod = "er ...