AtomicInteger 源码分析阅读

?

阅读java源码可能是每一个java程序员的必修课,只有知其所以然,才能更好的使用java,写出更优美的程序,阅读java源码也为我们后面阅读java框架的源码打下了基础。阅读源代码其实就像再看一篇长篇推理小说一样,不能急于求成,需要慢慢品味才行。这一系列的文章,记录了我阅读源码的收获与思路,读者也可以借鉴一下,也仅仅是借鉴,问渠那得清如许,绝知此事要躬行!要想真正的成为大神,还是需要自己亲身去阅读源码而不是看几篇分析源码的博客就可以的。

正文

最近在看JAVA1.8线程池源码的时候,发现对于AtomicInteger类的使用不太熟悉,所以就专门研究了一下,有一些收获。AtomicInteger是juc(java.util.concurrent)包下提供的一个可以原子性操作Integer对象的类。通过它,我们可以很方便的对Integer进行线程安全的加、减、改值等操作。其原理是使用的CAS无锁算法。

private static final long serialVersionUID = 6214790243416807050L;

// setup to use Unsafe.compareAndSwapInt for updates

//JAVA实现CAS算法的类,整个类有关线程安全的操作,都是借助它来实现。

private static final Unsafe unsafe = Unsafe.getUnsafe();

//变量value的内存首地址的偏移量。

private static final long valueOffset;

//静态代码块,在类加载时运行

static {

try {

valueOffset = unsafe.objectFieldOffset

(AtomicInteger.class.getDeclaredField(value));

} catch (Exception ex) { throw new Error(ex); }

}

//存放int值

private volatile int value;

1.unsafe 其实就是负责与CAS相关的操作实现。
2.valueOffset的值是变量value的内存首地址的偏移量。,它在AtomicInteger被加载时就被赋值了。
3.value其实就是存放实际值的变量,它被volatile 关键字修饰,说明对于其他线程是可见的。
可能大家还是不大能够了解valueOffset到底是个什么东西,有什么用,当时我也在这里卡了很久,接下来我来讲一下自己的分析过程。首先从字面意思来讲,应该是和value有关的一个变量。再看它是由objectFieldOffset()这个方法的返回值进行赋值的。我们查看一下objectFieldOffset()的声明定义:
发现并没有任何描述,但是通过百度发现说是value在内存中首地址。出于严禁的角度,我就写了一个测试来看看:

public class Main {

public static void main(String[] args) {

AtomicInteger a=new AtomicInteger(1);

AtomicInteger b=new AtomicInteger(1);

int c=a.addAndGet(5);

b.addAndGet(4);

System.out.println(a.get());

System.out.println(c);

}

}

addAndGet()方法的定义与声明

这个测试中,我实例化了两个AtomicInteger 对象:a和b,同时在调用的方法addAndGet()中打了断点。
最后debug发现,两个变量的valueOffset值都为12。说明valueOffset就是value内存首地址的偏移量。到这里或许大家还想问,这个偏移应该是针对于什么的偏移呢?你偏移量总得有个参照位置吧。这里就要回到我们valueOffset的定义与赋值了。

private static final long valueOffset;

//静态代码块,在类加载时运行

static {

try {

valueOffset = unsafe.objectFieldOffset

(AtomicInteger.class.getDeclaredField(value));

} catch (Exception ex) { throw new Error(ex); }

}

我们可以看到,valueOffset 是一个静态常量,并且在类加载时就被赋值了。那么这个类在编译后的字节码是一定的,但是存放对象的首地址是随机的,所以这里的偏移应该是相对于对象实例的首地址。如果大家看不明白,请看下面这幅图,这幅图简介明了的描述了valueOffset 的含义。

再联系到AtomicInteger在调用unsafe接口时,都将this和valueOffset 作为传入参数(如下图),我们可以了解到unsafe实现的CAS算法是依赖底层实现的(因为方法声明有native关键字),我们为其提供具体的内存地址,即this+valueOffset ,就可以让其找到要进行原子性操作的变量value,并进行修改。
   

?

原文地址:https://www.cnblogs.com/qfdsj/p/9565812.html

时间: 2024-08-27 17:26:48

AtomicInteger 源码分析阅读的相关文章

AtomicInteger源码分析——基于CAS的乐观锁实现

AtomicInteger源码分析--基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及到清空寄存器,缓存数据.然后重新加载新的thread所需数据.当一个线程被挂起时,加入到阻塞队列,在一定的时间或条件下,在通过notify(),notifyAll()唤醒回来.在某个资源不可用的时候,就将cpu让出,把当前等待线程切换为阻

死磕 java并发包之AtomicInteger源码分析

问题 (1)什么是原子操作? (2)原子操作和数据库的ACID有啥关系? (3)AtomicInteger是怎么实现原子操作的? (4)AtomicInteger是有什么缺点? 简介 AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作. 还记得Unsafe吗?点击链接直达[死磕 java魔法类之Unsafe解析] 原子操作 原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不

AtomicInteger源码分析

问题背景 最近在看LinkedBlockingQueue看到了其中的count使用AtomicInteger修饰,之前也看过AtomicInteger的一些解释,也是似懂非懂的,今天深入的了解了其实现方式,学到了很多东西. 基础介绍 要对AtomicInteger有一个深入的认识,就必须要了解一下悲观锁和乐观锁.cpu是时分复用的,也就是把cpu的时间片,分配给不同的线程/进程轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及到清空寄存器,缓存数据.然后重新加载新

AtomicInteger源码分析——基于CAS的乐观锁实

1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及到清空寄存器,缓存数据.然后重新加载新的thread所需数据.当一个线程被挂起时,加入到阻塞队列,在一定的时间或条件下,在通过notify(),notifyAll()唤醒回来.在某个资源不可用的时候,就将cpu让出,把当前等待线程切换为阻塞状态.等到资源(比如一个共享数据)可用了,那么就将线程唤醒,

Thrift源码分析阅读(二)

Thrift总结 总体结构: Server: ServerSocket监听请求,请求到达时,读取请求数据. 根据请求数据创建一个InputTransport,创建OutputTransport 根据InputTransport和OutputTransport创建相应的input protocol 和 output protocol. 依据protocol 创建processor,在processor中完成业务分发操作. 将请求信息结果数据写回客户端. Transport: 提供了一个读取/写入网

Thrift源码分析阅读(一)

Thrift -Storm篇 从Nimbus启动说起: 当用户通过命令启动nimbus时,Classloader将会找到一个称之为bytetype.storm.daemon.nimbus的一个class文件,这个是由numbis.clj文件编译而成,来看nimbus.clj这个的启动方法: (defn -main [] (-launch (standalone-nimbus))) (standalone-nimbus) 执行这个方法返回一个INimbus接口的实例 执行launch(INimbu

JDK源码分析-AtomicInteger

AtomicInteger可以看做Integer类的原子操作工具类.在java.util.concurrent.atomic包下,在一些使用场合下可以取代加锁操作提高并发性.接下来就从几个方面来介绍: 1.原子性和CAS. 2.CPU底层实现原理. 3.atomic包介绍. 4.源码分析. 原子性和CAS 原子性就是指某一个操作是不可拆分的,是一个整体必须要一次性全部执行完成要么就不执行. CAS是Compare And Swap(比较并交换).意思是当你要更新某个值的时候先要检查这个变量的当前

阅读《RobHess的SIFT源码分析:综述》笔记

今天总算是机缘巧合的找到了照样一篇纲要性质的文章. 如是能早一些找到就好了.不过“在你认为为时已晚的时候,其实还为时未晚”倒是也能聊以自慰,不过不能经常这样迷惑自己,毕竟我需要开始跑了! 就照着这个大纲往下走走,说不定会有意想不到的收获,然后把多视点的问题加进去,或许应该能有所成效. 嗯,其他的太多的东西想来也无用. 我觉得现在比较重要的事情是,顺着这样一篇文章继续我要做的东西. 原文<RobHess的SIFT源码分析:综述>地址: http://blog.csdn.net/masibuaa/

memcached源码分析-----安装、调试以及如何阅读memcached源码

        转载请注明出处:http://blog.csdn.net/luotuo44/article/details/42639131 安装: 安装memcached之前要先安装Libevent.现在假定Libevent安装在/usr/local/libevent目录了. 因为memcached安装后不像Libevent那样,有一堆头文件和库文件.安装后的memcached不是用来编程而直接用来运行的.所以不需要在/usr/local目录下专门为memcached建立一个目录.直接把mem