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

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


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. LeetCode包括main函数的答题框架(Java+Eclipse)

    http://zhangnai.xin/2016/09/20/LeetCode-Framework/ 目录结构: LeetCode ——项目名称,方便Eclipse内置Git对代码进行管理和多终端同步 ...

  2. [leetcode]199. Binary Tree Right Side View二叉树右视图

    Given a binary tree, imagine yourself standing on the right side of it, return the values of the nod ...

  3. MongoDB安装(一)

    详细图解,记录 win7 64 安装mongo数据库的过程.安装的版本是 MongoDB-win32-x86_64-2008plus-ssl-3.4.1-signed. 示例版本:mongodb-wi ...

  4. 21-js 实现评论时间格式转化

    js里面要用可以用伊尔表达式,循环是用js: document.getElementById("${pj.pltime }").innerHTML = dateToGMT(&quo ...

  5. sobel 使用说明

    转自http://www.cnblogs.com/justany/archive/2012/11/23/2782660.html OpenCV 2.4+ C++ 边缘梯度计算 2012-11-23 0 ...

  6. datagridview 如何禁止行被选中

    如题,如何规定特定的行,光标不能定位,也不能被选中,就好想Button中的Enable属性那样,变灰,而且点击也没有反应那种,这样的效果,如何实现. datagridview [解决办法]dataGr ...

  7. 面向对象与基于对象 学习记录 thread举例

    /********************************************************************/* @file* @author def< qq gr ...

  8. dotnet core 发布环境变量配置 dev/stage/prod

    https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/environments?view=aspnetcore-2.2 https://d ...

  9. 2018.09.11 poj1845Sumdiv(质因数分解+二分求数列和)

    传送门 显然需要先求出ab" role="presentation" style="position: relative;">abab的所有质因 ...

  10. 类内初始值(c++11)

    1.概念 1)可以为数据成员提供一个类内初始值,创建对象时,类内初始值用于初始化数据成员,没有初始值的成员将被默认初始化 2)类内初始值和赋值类似,或者放在花括号里(如数组),或者放在等号右边,不能使 ...