设为首页 加入收藏

TOP

对 volatile、compareAndSet、weakCompareAndSet 的一些思考(三)
2017-12-18 12:36:57 】 浏览:900
Tags:volatile compareAndSet weakCompareAndSet 一些 思考
保证了写操作后将线程本地内存(可能包含了多个缓存行)中所有的共享变量值都刷新到主内存中。这样其他线程总是能在volatile写操作后的读取操作中得到该线程中所有共享变量的正确值。这是volatile的happens-before关系( 通过内存屏障实现 )带给我们的结果。注意,这个和volatile变量自身的特性是不同的,volatile自身仅仅是保证了volatile变量本身的可见性。而volatile的happens-before关系则保证了操作不会被重排序同时保证了线程本地内存中所有共享变量的可见性。

好了,讨论到这里,我们重新来理解下weakCompareAndSet的实现语义。也就是说,weakCompareAndSet操作仅保留了volatile自身变量的特性,而出去了happens-before规则带来的内存语义。也就是说,weakCompareAndSet无法保证处理操作目标的volatile变量外的其他变量的执行顺序( 编译器和处理器为了优化程序性能而对指令序列进行重新排序 ),同时也无法保证这些变量的可见性。

源码实现

目前为止,我们已经能够明白compareAndSet方法和weakCompareAndSet方法的不同之处了。那么,接下来我们来看看这两个方法的具体实现:

public boolean compareAndSet(T obj, int expect, int update) {
    if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    return unsafe.compareAndSwapInt(obj, offset, expect, update);
}

public boolean weakCompareAndSet(T obj, int expect, int update) {
    if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    return unsafe.compareAndSwapInt(obj, offset, expect, update);
}

是的,你没有看错。这两个方法的实现完全一样。。『unsafe.compareAndSwapInt(obj, offset, expect, update);』中就是调用native方法了:

inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
     int mp = os::is_MP();
     __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                     : "=a" (exchange_value)
                     : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                      : "cc", "memory");
     return exchange_value;
}

由此可见,在JDK8乃至之前的版本,weakCompareAndSet方法并没有被真是意义上的实现,目前该方法所呈现出来的效果与compareAndSet方法是一样的。

基于JDK 9

在JDK 9中 compareAndSet 和 weakCompareAndSet方法的实现有些许的不同

/**
 * Atomically updates Java variable to {@code x} if it is currently
 * holding {@code expected}.
 *
 * <p>This operation has memory semantics of a {@code volatile} read
 * and write.  Corresponds to C11 atomic_compare_exchange_strong.
 *
 * @return {@code true} if successful
 */
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetInt(Object o, long offset,
                                             int expected,
                                             int x);

① 底层调用的native方法的实现中,cmpxchgb指令前都会有“lock”前缀了(在JDK 8中,程序会根据当前处理器的类型来决定是否为cmpxchg指令添加lock前缀。只有在CPU是多处理器(multi processors)的时候,会添加一个lock前缀)。

② 同时多了一个@HotSpotIntrinsicCandidate注解,该注解是特定于Java虚拟机的注解。通过该注解表示的方法可能( 但不保证 )通过HotSpot VM自己来写汇编或IR编译器来实现该方法以提供性能。
它表示注释的方法可能(但不能保证)由HotSpot虚拟机内在化。如果HotSpot VM用手写汇编和/或手写编译器IR(编译器本身)替换注释的方法以提高性能,则方法是内在的。

也就是说虽然外面看到的在JDK9中weakCompareAndSet和compareAndSet底层依旧是调用了一样的代码,但是不排除HotSpot VM会手动来实现weakCompareAndSet真正含义的功能的可能性。

后记

嗯,关于compareAndSet与weakCompareAndSet两个方法的不同,看似可能是个“简单”的问题,但当我真的去探究它们的不同时,还是话费了我不少的时间,同时也让我对volatile有了更加深入的理解。这里关于CAS还有不少值得深入探讨的地方,值得再用一篇文章好好的进行叙说。关于JDK9的改变也是值得以后慢慢去探索的。

参考

  • 《Java 并发编程的艺术》
首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇编写高质量代码的思考 下一篇Java 线程池框架核心代码分析

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目