`
喻红叶
  • 浏览: 39484 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

Java并发-AtomicInteger源码分析

阅读更多

CAS

CAS(Compare-And-Swap,比较并交换)操作是CPU中术语,它保证了操作的原子性。CAS指令需要三个操作数,分别是:

V:内存位置(也就是本次操作变量的内存地址);

A:旧的预期值;

B: 操作完成后的新值。

CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行更新,无论是否更新,都会返回V的旧值,整个CAS操作是一个原子操作。在JDK1.5之后,Java程序中才可以使用CAS操作,该操作由sun.misc.Unsafe类里的compareAndSwapXXX()方法包装提供,虚拟机在内部对这些方法做了特殊处理。在JDK1.5中提供了原子变量,如AtomicInteger,AtomicLong等,由并发大师Doug Lea操刀,提供了在单个变量上面不需要锁的线程安全性。现在就让我们走进AtomicInteger的世界中,探究它是如何实现的,并领略大师的风采。

AtomicInteger中原子操作的实现

通过这一小部分的分析,我们就弄明白了AtomicInteger中原子操作的实现,首先看看AtomicInteger中有哪些状态

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    //使用Unsafe.compareAndSwapInt来执行修改操作,CAS是通过Unsafe.compareAndSwapXXX()方法实现的
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    //value在内存中的地址偏移量
    private static final long valueOffset;

    static {
      try {
    	//获得value的内存地址偏移量
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
      } catch (Exception ex) { throw new Error(ex); }
    }
    //当前对象代表的值,注意是volatile
    private volatile int value;

在这一段代码中,我们需要注意三个方面,也就是AtomicInteger的三个字段:

(1)unsafe字段,AtomicInteger包含了一个Unsafe类的实例,unsafe就是用来实现CAS的;

(2)value字段,表示当前对象代码的基本类型的值,AtomicInteger是int型的线程安全包装类,value就代码了AtomicInteger的值。注意,这个字段是volatile的。

(3)valueOfset,通过字面意思就可以看出来valueOfset是value在内存中的偏移量,也就是在内存中的地址,通过Unsafe.objectFieldOffset(Field f)获取。前面在讲CAS时,我们提到需要操作内存的位置,valueOfset就是这个位置。

AtomicInteger中的CAS

public final boolean compareAndSet(int expect,int update)就是CAS的具体实现,其他所有的原子操作都是依赖于此方法,前面已经提到了,Java中的CAS是通过Unsafe类实现的,这个方法就是通过调用Unsafe.compareAndSwapInt(this,valueOfset,expect,udate)方法来实现的,其中valueOffset就是要操作的内存地址,expect是旧值,update是新值,当且仅当valueOffset内存中的值等于expect时,才用update更新旧值。其代码如下:

/**
     * 原子操作
     * CAS:Compare-and-Swap
     * 如果当前值==expect,则设置新值
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
AtomicInteger提供了好几个原子操作变量的方法:

int addAndGet(intdelta)
将当前值与给定的值相加,并返回新值
boolean compareAndSet(intexpect, intupdate)
当且仅当value==expect,value=update
int decrementAndGet()
自减1,并返回新值
int getAndAdd(intdelta)
将当前值与给定值相加,并返回相加之前的值(旧值)
int getAndDecrement()
自减1,并返回旧值
int getAndIncrement()
自增1,并返回旧值
int getAndSet(intnewValue)
将当前值与给定值相加,并返回旧值
int incrementAndGet()
自增1,并返回新值

可以看到,每一种操作(自增,自减,加给定值)都提供了对称的操作,其中getAndXXX()方法是返回旧值,XXXAndGet()返回的是新值。这些操作的实现方式都是相同的,我们以getAndIncrement()为例,来讲解它是如何实现原子操作的。首先看getAndIncrement()的源码:

/**
     * 原子操作,实现自增操作,通过CAS实现,返回自增之前的值
     * 实现原理是这样的:
     * 1.首先获得当前值,保存到current中,next=current + 1
     * 2.如果CAS成功,则返回current
     *   如果CAS不成功,这说明刚刚有其他的线程修改了当前值,current已经失效了,next也已经失效了
     *   只能重新获取当值,并继续CAS,直到成功为止
     */
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }
在上面的注释中已经说的比较明白了,但我还是愿意再啰嗦两句:

(1)首先获得当前值,保存到current中,并把current的下一个值保存到next中,next=current+1

(2)调用compareAndSet(current,next)尝试自增,如果自增成功,则返回current;如果自增失败,则说明已经有其他线程修改value的值,current中的值和next中的值已经失效了,要重新获取当前值,重复刚才的CAS操作,直到成功位置。

可以看到,通过第(2)步的操作,确实实现了多线程下的安全,即使在自增的时候有其他线程修改了当前值,自增操作也不会覆盖已经修改的值,而是在当前最新值的基础上实现自增。演示一下不使用CAS的错误情况和这种实现方式的正确性

a.错误的自增,假设当前value=8,同时有两个线程t1,t2对value执行自增操作,执行顺序如下:


执行完成后,t2的值把t1的值给覆盖了,执行完成后,现在value=9,正确的结果应该是10。在下图中,通过CAS以同样的顺序执行,获得的结果就是正确的:


上面的分析基本上就概括了AtomicInteger实现的全部了。但是CAS并不是没有缺点,概括起来说,CAS就三个缺点:

(1)ABA问题,如果V的初始值是A,在准备赋值的时候检查到它仍然是A,那么能说它没有改变过吗?也许V经历了这样一个过程:它先变成了B,又变成了A,使用CAS检查时以为它没变,其实却变里;

(2)循环时间长,开销大,通过自旋CAS一直在消耗CPU

(3)只能保证一个共享变量的原子操作,当对多个共享变量操作时就无法保证原子性了。

AtomicInteger源码分析

package com.java.source;

import sun.misc.Unsafe;

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    //使用Unsafe.compareAndSwapInt来执行修改操作,CAS是通过Unsafe.compareAndSwapXXX()方法实现的
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    //value在内存中的地址偏移量
    private static final long valueOffset;

    static {
      try {
    	//获得value的内存地址偏移量
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
      } catch (Exception ex) { throw new Error(ex); }
    }
    //当前对象代表的值,注意是volatile
    private volatile int value;

    /*使用给定的值创建对象,也就是把给定的值包装起来*/
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    /*默认初始化为0*/
    public AtomicInteger() {
    }
    
    /*getter/setter*/
    public final int get() {
        return value;
    }
    public final void set(int newValue) {
        value = newValue;
    }

    /*最后设置指定的值*/
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

   /*原子操作:设定新值,返回旧值,通过CAS完成*/
    public final int getAndSet(int newValue) {
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }

    /**
     * 原子操作
     * CAS:Compare-and-Swap
     * 如果当前值==expect,则设置新值
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 原子操作,功能与compareAndSet一样
     * 有可能意外失败,且不保证排序,但是调用的代码是完全一样的,JVM又在内部做了手脚?
     * 在极少情况下用来替代compareAndSet
     */
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 原子操作,实现自增操作,通过CAS实现,返回自增之前的值
     * 实现原理是这样的:
     * 1.首先获得当前值,保存到current中,next=current + 1
     * 2.如果CAS成功,则返回current
     *   如果CAS不成功,这说明刚刚有其他的线程修改了当前值,current已经失效了,next也已经失效了
     *   只能重新获取当值,并继续CAS,直到成功为止
     */
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

    /**
     * 原子操作,实现自减,通过CAS实现,返回当前值
     * 实现方法同getAndIncrement()相同
     */
    public final int getAndDecrement() {
        for (;;) {
            int current = get();
            int next = current - 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

    /**
     * 原子操作,将当前值增加delta,并返回当前值
     * 实现原理同getAndIncrement()相同,只不过一个是增1,一个是增delta
     */
    public final int getAndAdd(int delta) {
        for (;;) {
            int current = get();
            int next = current + delta;
            if (compareAndSet(current, next))
                return current;
        }
    }

    /*原子操作,自增一,并返回增加后的值*/
    public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

   /*原子操作,自减,并返回减小后的值*/
    public final int decrementAndGet() {
        for (;;) {
            int current = get();
            int next = current - 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

    /*原子操作,增加delta,并返回增加后的操作*/
    public final int addAndGet(int delta) {
        for (;;) {
            int current = get();
            int next = current + delta;
            if (compareAndSet(current, next))
                return next;
        }
    }

   /**
    * 一些常规方法
    */
    public String toString() {
        return Integer.toString(get());AtomicLong
    }

    
    public int intValue() {
        return get();
    }

    public long longValue() {
        return (long)get();
    }

    public float floatValue() {
        return (float)get();
    }

    public double doubleValue() {
        return (double)get();
    }

}
转载请注明出处:喻红叶《Java并发-AtomicInteger源码分析》

分享到:
评论

相关推荐

    java并发之AtomicInteger源码分析

    AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。下面小编和大家一起学习一下

    Java并发编程相关源码集 包括多任务线程,线程池等.rar

    Java并发编程常见知识点源码集锦,涉及到对象锁,Executors多任务线程框架,线程池等示例,列出一些源码包中包括的内容:  volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小...

    java并发工具包 java.util.concurrent中文版用户指南pdf

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    java并发工具包详解

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf

    java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    Java中对AtomicInteger和int值在多线程下递增操作的测试

    主要介绍了Java中对AtomicInteger和int值在多线程下递增操作的测试,本文得出AtomicInteger操作 与 int操作的效率大致相差在50-80倍上下的结论,需要的朋友可以参考下

    AtomicInteger并发测试

    测试java.util.concurrent.atomic.AtomicInteger的类 与直接使用int做区别

    汪文君高并发编程实战视频资源下载.txt

     高并发编程第三阶段11讲 AtomicXXXFieldUpdater源码分析及使用场景分析.mp4  高并发编程第三阶段12讲 sun.misc.Unsafe介绍以及几种Counter方案性能对比.mp4  高并发编程第三阶段13讲 一个JNI程序的编写,通过...

    汪文君高并发编程实战视频资源全集

     高并发编程第三阶段11讲 AtomicXXXFieldUpdater源码分析及使用场景分析.mp4  高并发编程第三阶段12讲 sun.misc.Unsafe介绍以及几种Counter方案性能对比.mp4  高并发编程第三阶段13讲 一个JNI程序的编写,通过...

    Java AtomicInteger类的使用方法详解

    主要介绍了Java AtomicInteger类的使用方法详解,文中有具体实例代码,具有一定参考价值,需要的朋友可以了解下。

    Java AtomicInteger类使用方法实例讲解

    主要介绍了Java AtomicInteger类使用方法实例讲解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    java并发包资源

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    java编发编程:JUC综合讲解

    Java 并发编程在现代软件开发中占据重要地位,尤其是在多核处理器的时代。JUC(java.util.concurrent)库是 Java 标准库的一部分,提供了丰富的多线程并发工具,旨在帮助开发者编写高性能、高可伸缩性的并发程序。...

    使用Java的Memory Model实现一个简单的计数器.txt

    这个代码实现了一个简单的计数器,使用了Java的`AtomicInteger`类来保证多线程环境下的原子性操作。`AtomicInteger`是一个支持原子操作的整数类,它内部使用了CAS(Compare And Swap)算法来实现线程安全的操作。在...

    java 分页、批量删除

    包含了jsp的简单分页,有首页、尾页、上下页、设置页面数字等,有完整的注释、包、ppt等,mysql数据库的,对后台管理的删除有不错的参考价值,非常适合web初学者,改改就可以在多少场合运用。

    用Java代码所写的简单计数器

    用Java代码所写的简单计数器,功能:根据选票人投票,最后记录数据并用立方图显示结果

    AtomicInteger 浅谈

    NULL 博文链接:https://zcmor.iteye.com/blog/1535524

    java8集合源码-IteRace:Java并行循环的竞争检测

    java8集合源码赛马 IteRace 是伊利诺伊大学开发的静态竞态检测工具。 静态竞争检测器存在不精确性(由于保守的假设),这通常表现为程序员需要检查的数量难以管理的警告。 ItRace 通过专业化来解决这个问题: 它了解...

    JUC多线程学习个人笔记

    JUC(Java Util Concurrent)是Java中用于并发编程的工具包,提供了一组接口和类,用于处理多线程和并发操作。JUC提供了一些常用的并发编程模式和工具,如线程池、并发集合、原子操作等。 JUC的主要特点包括: ...

Global site tag (gtag.js) - Google Analytics