文档章节

java.util.concurrent的AtomicInteger类详解

wangtx
 wangtx
发布于 2016/05/11 23:18
字数 949
阅读 479
收藏 4
点赞 2
评论 0

java.util.concurrent包下面有很多原子性的线程安全的数据结构的实现。研究一下常用的AtomicInteger类。

AtomicInteger类对应着常用的int类型,看一下它如何实现原子性的。

static {
  try {
    valueOffset = unsafe.objectFieldOffset
        (AtomicInteger.class.getDeclaredField("value"));
  } catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
public AtomicInteger(int initialValue) {
    value = initialValue;
}
public AtomicInteger() {
}

static块里面的看不懂。里面的unsafe会在后面提到。

下面的代码可以看出,基本的数据存数是靠volatile int value来实现的。

但是volatile关键字是实现不了并发安全的(volatile关键字详解),他对数据操作的方法肯定是还有其他原因。

get()、set()等不对原有值依赖的方法volatile就可以实现期望的功能。我们看一下

getAndIncrement()、incrementAndGet()等方法是如何实现的。
public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

关键的是compareAndSet(current,next)方法的实现。

/**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

可以看到它的注解说明,当value与当前期望的值相等的时候,原子性的更新value。照这样说就实现了并发安全,但他到底怎么实现的呢?

下面是Unsafe类中的方法

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

不是用Java实现的, 而是通过JNI调用操作系统的原生程序.通常情况下周到这里就停止了,但在网上找了一下,有说明,水平还没到能自己往下搞明白。

下面都是截取的网上的说明:

compareAndSwapInt的native实现
如果你下载了OpenJDK的源代码的话在hotspot\src\share\vm\prims\目录下可以找到unsafe.cpp

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

可以看到实际上调用Atomic类的cmpxchg方法.

Atomic的cmpxchg
这个类的实现是跟操作系统有关, 跟CPU架构也有关, 如果是windows下x86的架构
实现在hotspot\src\os_cpu\windows_x86\vm\目录的atomic_windows_x86.inline.hpp文件里

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  // alternative for InterlockedCompareExchange
  int mp = os::is_MP();
  __asm {
    mov edx, dest
    mov ecx, exchange_value
    mov eax, compare_value
    LOCK_IF_MP(mp)
    cmpxchg dword ptr [edx], ecx
  }
}

在这里可以看到是用嵌入的汇编实现的, 关键CPU指令是 cmpxchg
到这里没法再往下找代码了. 也就是说CAS的原子性实际上是CPU实现的. 其实在这一点上还是有排他锁的. 只是比起用synchronized, 这里的排他时间要短的多. 所以在多线程情况下性能会比较好.

代码里有个alternative for InterlockedCompareExchange
这个InterlockedCompareExchange是WINAPI里的一个函数, 做的事情和上面这段汇编是一样的
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560%28v=vs.85%29.aspx

最后再贴一下x86的cmpxchg指定

Opcode CMPXCHG

CPU: I486+ 
Type of Instruction: User 

Instruction: CMPXCHG dest, src 

Description: Compares the accumulator with dest. If equal the "dest" 
is loaded with "src", otherwise the accumulator is loaded 
with "dest". 

Flags Affected:	AF, CF, OF, PF, SF, ZF 

CPU mode: RM,PM,VM,SMM 
+++++++++++++++++++++++ 
Clocks: 
CMPXCHG reg, reg	6 
CMPXCHG mem, reg	7 (10 if compartion fails) 

后面在网上截取的这段引自http://www.blogjava.net/mstar/archive/2013/04/24/398351.html

C语言的东西都忘干净了,看不太懂了,最后的CPU的实现更看不明白了。但是知道了它是并发安全的是在cpu层实现的,目测效率应该比synchronized高。

这里还有两篇文章,一篇是Volatile、AtomicLong、synchronized三者效率的http://hehongwei44.iteye.com/blog/1244732

一篇是volatile正确使用场景的http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

© 著作权归作者所有

共有 人打赏支持
wangtx
粉丝 6
博文 24
码字总数 18965
作品 0
济南
程序员
【转】 Java 并发工具包 java.util.concurrent 用户指南

http://blog.csdn.net/defonds/article/details/44021605译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.jenkov.com/java-util-concurrent/index.html。......

围城以北 ⋅ 2016/03/09 ⋅ 0

Java CAS操作的ABA问题

CAS介绍 比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预...

ksfzhaohui ⋅ 2016/11/22 ⋅ 4

Java 并发工具包 java.util.concurrent 用户指南

译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.jenkov.com/java-util-concurrent/index.html。 本指南已做成中英文对照阅读版的 pdf 文档,有兴趣的朋友...

pior ⋅ 2015/10/26 ⋅ 0

队列 LinkedBlockingQueue

1 api java.util.concurrent包下的新类。LinkedBlockingQueue就是其中之一,是一个阻塞的线程安全的队列,底层采用链表实现。 LinkedBlockingQueue构造的时候若没有指定大小,则默认大小为I...

光斑 ⋅ 04/09 ⋅ 0

java.util.concurrent.atomic与CAS详解

一、CAS(Compare And Swap) 顾名思义,CAS就是比较与交换。具体解释如下: CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么...

阿阿阿阿阿局 ⋅ 2016/08/05 ⋅ 0

Java多线程三(线程安全的集合及java.util.concurrent包的锁)

一、线程安全的集合 JDK1.5之前,可以使用Venctor和Hashtable,也可以由java.util.Collections来创建线程安全的集合,如:Connections.synchronizedSet(Set<T>); Connections.synchronizedLi......

dkz ⋅ 2013/03/24 ⋅ 0

CAS非左塞同步算法

在java并发编程里要实现原子操作,大家都会想到同步(synchronize),这种同步会使线程左塞,在性能上不是很满意。基于CAS(Compare And Set) 可以实现非左塞同步算法。 何为cas? compare-an...

温佐镜 ⋅ 2014/01/29 ⋅ 0

LinkedBlockingQueue

介绍 LinkedBlockingQueue实现BlockingQueue接口. JDK中位置:java.util.concurrent包下,该包为并发包,同样LinkedBlockingQueue自身实现了并发处理,使用的是存取锁的方式. 自身还实现了读写分...

Adoniscx ⋅ 2013/12/19 ⋅ 0

[高并发Java 四] 无锁

在[高并发Java 一] 前言中已经提到了无锁的概念,由于在jdk源码中有大量的无锁应用,所以在这里介绍下无锁。 1 无锁类的原理详解 1.1 CAS CAS算法的过程是这样:它包含3个参数CAS(V,E,N)。V...

Hosee ⋅ 2016/01/11 ⋅ 1

并发编程(二)

1.java中的原子操作类: 原子操作是指程序编译后对应于一条CPU操作指令,即原子操作是最小的不可再分指令集,编程中的原子操作是线程安全的,不需要使用进行线程同步和加锁机制来确保原子操作...

凯文加内特 ⋅ 2014/02/13 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Python爬虫,抓取淘宝商品评论内容

作为一个资深吃货,网购各种零食是很频繁的,但是能否在浩瀚的商品库中找到合适的东西,就只能参考评论了!今天给大家分享用python做个抓取淘宝商品评论的小爬虫! 思路 我们就拿“德州扒鸡”...

python玩家 ⋅ 17分钟前 ⋅ 0

MySQL 内核深度优化

MYSQL数据库适用场景广泛,相较于Oracle、DB2性价比更高,Web网站、日志系统、数据仓库等场景都有MYSQL用武之地,但是也存在对于事务性支持不太好(MySQL 5.5版本开始默认引擎才是InnoDB事务...

java高级架构牛人 ⋅ 40分钟前 ⋅ 0

用户登录信息-钉子效果(基于jquery2.0)

本js效果使用jquery2.0,清晰的分解用户登录信息的(钉子效果),该效果直接用在作者网站(www.phpkhbd.com)上。 里面的难点有:定时器,延时。 大致效果如下: 一开始: 鼠标放上去的时候:...

宁哥实战课堂 ⋅ 41分钟前 ⋅ 0

解决yum安装报错Protected multilib versions

使用yum安装报错Protected multilib versions原因是因为多个库不能共存,不过更新的话也并不行,但是可以在安装命令后面加上如下一段命令: --setopt=protected_multilib=false 案例: 比如需...

北岩 ⋅ 52分钟前 ⋅ 0

为什么要学习Typescript???

简单来说 目前的typescript就是未来的javascript 为什么?? 这要从ECMA-262标准的第4版说起 对了 我们说的ES5 其实是ECMAScript3.1这个替代性建议被扶正了而已... 那么 第4版标准是什么? 看看...

hang1989 ⋅ 57分钟前 ⋅ 0

linux安装ipfs

一、下载ipfs # cd /usr/local/ipfs/ # wget https://dist.ipfs.io/go-ipfs/v0.4.15/go-ipfs_v0.4.15_linux-amd64.tar.gz # tar -zxvf go-ipfs_v0.4.15_linux-amd64.tar.gz 二、安装ipfs # ......

八戒八戒八戒 ⋅ 今天 ⋅ 0

jvm程序执行慢诊断手册

生产环境最多的几种事故之一就是程序执行慢,如果是web服务的话,表现就是响应时间长。本文分享,从业多年形成的排查守则。 诊断步骤 系统资源查看 首先是系统资源查看,而且必须是在第一步。...

xpbob ⋅ 今天 ⋅ 0

YII2 advanced 高级版本项目搭建-添加API应用以及多应用

一、YII安裝 安裝yii可以用composer安裝,也可以在yii中文社区下载归档文件安装 composer安装就不介绍了,因为要安装composer,比较麻烦,当然安装了composer是最好的,以后安装yii的插件要用...

botkenni ⋅ 今天 ⋅ 0

在jdk1.8的环境下模拟永久代内存溢出

相信不少小伙伴在看深入理解Java虚拟机的时候,作者给我们举例一个demo来发生PermGen space 1、通过List不断添加String.intern(); 2、通过设置对应的-XX:PermSize与-XX:MaxPermSize(更快看到...

虾几把写 ⋅ 今天 ⋅ 0

开发OpenDaylight组件的完整流程

在前面介绍学习了OpenDaylight的几个重要模块后,这里再来介绍下完整开发一个模块的过程。 OSGI的bundles提供被其他OSGI组件调用的服务。这个教程中展示的是Data Packet Service去解析数据包...

wangxuwei ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部