博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并发编程-Atomic的compareAndSet
阅读量:7214 次
发布时间:2019-06-29

本文共 2889 字,大约阅读时间需要 9 分钟。

接上一篇博客,分析Atomic原子类是怎么保证线程安全的。

并发三个基本概念:

1.原子性:操作是线程私有的,不能拆分成多个步骤,被其他线程影响;(官方版:操作不可中断,全部执行或全部失败)

2.可见性:对共享变量的修改能够被其他线程可见;

3.有序性:cpu会为了优化对指令进行重排序,有序性保证线程内指令顺序一致。

看AtomicInteger的incrementAndGet方法如何保证原子性的。以下代码是CAS的过程:

public final int incrementAndGet() {        for (;;) {            int current = get(); //从主内存中拷贝value放到本地线程栈内存中 这二行代码可能另一个线程也在执行            int next = current + 1; //做增加操作            if (compareAndSet(current, next))                 return next;        }    }//调用unsafe的compareAndSwapInt方法public final boolean compareAndSet(int expect, int update) {        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);    }public final int get() {        return value;    }private volatile int value;  //volatile保证了可见性,在incrementAndGet()方法中get()方法获取的value是从主内存中拿到的
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static {        try {         valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); //获取value值在AtomicInteger内存地址中的偏移量
} catch (Exception ex)         { throw new Error(ex); } } //Unsafe class 代码 public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

原理就是:线程A从主存中拿到value值,对value值做+1操作赋给newValue,然后再获取一次主内存的值,比较value和原值是否相等,如果相等,证明这个值没有被别的线程改变,对它设置新的值,如果不相等,证明这个值被别的线程更改了,重新获取一次,再次比较,直到相等、设置新值,返回新值。

再来看一下compareAndSwapInt方法 unsafe.cpp,(http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/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(x, addr, e)  继续看Atomic::cmpxchg , 这个本地方法的最终实现在openjdk的如下位置:

openjdk-7-fcs-src-b147-27jun2011\openjdk\hotspot\src\oscpu\windowsx86\vm\atomicwindowsx86.inline.hpp (对应于windows操作系统,X86处理器)
// Adding a lock prefix to an instruction on MP machine// VC++ doesn't like the lock prefix to be on a single line// so we can't insert a label after the lock prefix.// By emitting a lock prefix, we can define a label after it.#define LOCK_IF_MP(mp) __asm cmp mp, 0  \                       __asm je L0      \                       __asm _emit 0xF0 \                       __asm L0: 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  }}
LOCK_IF_MP指的是如果是在多核环境时,cpu会加上lock,如果是单核环境,不会加lock,因此实际上也是通过lock在cpu层面加上了屏障,排他锁。但是cpu层面的锁比jvm层的sync锁 效率要高很多。
 

转载于:https://www.cnblogs.com/zhengwangzw/p/9363654.html

你可能感兴趣的文章
英特尔在移动市场另辟蹊径
查看>>
英特尔收购Movidius背后:为什么我们需要一款专门的CV处理芯片?
查看>>
三大新闻机构起诉FBI,FBI与苹果大战续集开幕?
查看>>
未来数据中心的选择:宽带多模光纤
查看>>
信息安全隐患日趋严重 专家呼吁政策监管仍待加强
查看>>
Java 代理(proxy)模式
查看>>
转型不该只是一句空话 还应该有更多实质
查看>>
在QTP中申明XPath
查看>>
端到端加密(E2EE)技术分析:在移动应用中实现安全通信的利器
查看>>
信息安全 CIO最关注什么?
查看>>
物联网是怎样把世界联系起来的
查看>>
大数据在统计中的应用初探
查看>>
IBM与思科在融合型基础设施领域实现另一突破
查看>>
《深入理解Elasticsearch(原书第2版)》——第2章 查询DSL进阶 2.1 Apache Lucene默认评分公式解释...
查看>>
三星对外发售高性能芯片,华为上升势头或受重击!
查看>>
TOP10全球ICT技术发展趋势
查看>>
经济参考报:"想哭"病毒为中国网络安全敲警钟
查看>>
全新WiFi技术问世 更适合智能家庭和物联网
查看>>
【云和恩墨大讲堂】Oracle线上嘉年华第二讲
查看>>
刘宇与小白健康:一个理想主义者的互联网“众包”实践
查看>>