文档章节

java.util.concurrent的AtomicInteger类详解

wangtx
 wangtx
发布于 2016/05/11 23:18
字数 949
阅读 549
收藏 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
粉丝 7
博文 32
码字总数 22979
作品 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...

光斑
2018/04/09
0
0
原子变量、volatile、synchronized的可见性和原子性比较

jdk5提供了java.util.concurrent包,这个包并行功能强大,工具齐全,其中就包括原子变量atomic 那么我们先说说volatile,volatile可以保证内存的可见性,禁用重排序,但是不能保证操作的原子性...

AI9o後
2017/11/03
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生成二维码图片

maven配置jar包 <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>com.google.z......

骑羊放狼灬
7分钟前
2
0
oracle 修改字段类型

1.varchar2 类型修改 例子:alter table T_Node modify (NODE_CONTEXT varchar2(4000)); 2.varchar2 修改为clob 例子: alter table T_Node add hehe clob; update T_Node set hehe=NODE_CO......

qimh
11分钟前
2
0
别再写 bug 了,避免空指针的 5 个案例!

空指针是我们 Java 开发人员经常遇到的一个基本异常,这是一个极其普遍但似乎又无法根治的问题。 本文,栈长将带你了解什么是空指针,还有如何有效的避免空指针。 什么是空指针? 当一个变量...

Java技术栈
15分钟前
5
0
FastJson对BigDecimal保留两位小数(valueFilter)

实现ValueFilter public class BigDecimalValueFilter implements ValueFilter { @Override public Object process(Object o, String name, Object value) {//o是待转换的对象,n......

石日天
17分钟前
1
0
android 颜色透明度参照比

##透明度参照表: 00%=FF(不透明) 5%=F2 10%=E5 15%=D8 20%=CC 25%=BF 30%=B2 35%=A5 40%=99 45%=8c 50%=7F 55%=72 60%=66 65%=59 70%=4c 75%=3F 80%=33 85%=21 90%=19 95%=0c 100%=00(全透......

东街小霸王
17分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部