文档章节

java.util.concurrent的AtomicInteger类详解

wangtx
 wangtx
发布于 2016/05/11 23:18
字数 949
阅读 532
收藏 4

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
博文 28
码字总数 20415
作品 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
50
0
Java CAS操作的ABA问题

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

ksfzhaohui
2016/11/22
1K
4
队列 LinkedBlockingQueue

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

光斑
04/09
0
0
Java 并发工具包 java.util.concurrent 用户指南

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

pior
2015/10/26
0
0
Java并发编程-并发工具包java.util.concurrent使用指南

https://blog.csdn.net/axi295309066/article/details/65665090 译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新 本指南已做成中英文对照阅读版的 pdf 文档,有兴趣的朋友可...

毛朱
09/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Linux学习-1031(rsync同步工具 上)

10.28 rsync工具介绍 10.29/10.30 rsync常用选项 10.31 rsync通过ssh同步 一、 rsync工具介绍 rsync是一个同步工具,在日常的运维中常会用到。它可以本地同步,也实现可以远程两台机器同步。...

wxy丶
3分钟前
0
0
python实战一期:第一天

1. 为什么学习python 1.1 为什么要学Python? Python第一是个非常牛B的脚本语言,能满足绝大部分自动化运维的需求,又能做后端C/S架构,又能用WEB框架快速开发出高大上的Web界面,只有当你自...

laoba
6分钟前
0
0
Java并发编程学习三:线程同步的关键字以及理解

上篇文章中介绍了Java线程的带来的问题与内存模型中介绍了线程可能会引发的问题以及对应Java的内存模型,顺带介绍了Volatile和Sychronized关键字。今天对Java中涉及到的常见的关键类和关键字...

JerryLin123
12分钟前
0
0
我用代码来给你们分析一个赚钱的技巧

赚钱是个俗气的话题,但又是人人都绕不开的事情。我今天来“科学”地触碰下这个话题。 谈赚钱,就会谈到理财、投资,谈到炒股。有这样一个笑话: 问:如何成为百万富翁? 答:带一千万进入股...

crossin
12分钟前
0
0
spring MatchingBean应用

1、编写接口FactoryList import java.util.List;public interface FactoryList<E extends MatchingBean<K>, K> extends List<E> { E getBean(K factor); List<E> getBeanLi......

重城重楼
26分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部