JDK中的CAS实现

2021/5/28 Java多线程

# AtomicInteger实现

// AtomicInteger.java
public final int incrementAndGet() {
    //如果写入失败,死循环重试
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

public final boolean compareAndSet(int expect, int update) {
    //调用Unsafe类提供的native方法
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

// Unsage.java
public final native boolean compareAndSwapInt(Object target, long offset, int expect, int value);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 示例:直接使用Unsafe修改对象属性

public class T06_UnsafeSwap {
    
    int value;
    
    public static void main(String[] args) throws Exception {
        //构造方法私有,通过反射获取实例
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);

        //获取value的offset
        Field field = T06_UnsafeSwap.class.getDeclaredField("value");
        long offset = unsafe.objectFieldOffset(field);
        System.out.println(offset);

        //执行CAS操作
        T06_UnsafeSwap target = new T06_UnsafeSwap();
        boolean result = unsafe.compareAndSwapInt(target, offset, 0, 1);
        System.out.println(result);
        System.out.println(target.value);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# JDK8中unsafe的实现

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
1
2
3
4
5
6

cmpxchg: compare and exchange set swap

atomic_linux_x86.inline.hpp

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;
}
1
2
3
4
5
6
7
8

os.hpp is_MP()

static inline bool is_MP() {
    // During bootstrap if _processor_count is not yet initialized
    // we claim to be MP as that is safest. If any platform has a
    // stub generator that might be triggered in this phase and for
    // which being declared MP when in fact not, is a problem - then
    // the bootstrap routine for the stub generator needs to check
    // the processor count directly and leave the bootstrap routine
    // in place until called after initialization has ocurred.
    return (_processor_count != 1) || AssumeMP;
}
1
2
3
4
5
6
7
8
9
10

LOCK_IF_MP 判断是否拥有多个逻辑CPU,如果是,需要加锁。
加锁的方式是给cmpxchg指令前曾加lock指令。
lock指令会在执行的时候视情况采用缓存锁或者总线锁。

最终执行:lock cmpxchg 指令