CAS中,如何避免比较和修改之间插入线程?

这说的并不是ABA问题,ABA问题是比较之前某个值被改变成另一个相同的值的问题

先来回顾原语:原子性的语句,就是一堆机器指令,CPU要么全部执行,要么全部不执行

JAVA中的CAS:

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5)

查看其native源码:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
  UnsafeWrapper("Unsafe_CompareAndSwapObject");
  oop x = JNIHandles::resolve(x_h); // 新值
  oop e = JNIHandles::resolve(e_h); // 预期值
  oop p = JNIHandles::resolve(obj);
  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);// 在内存中的具体位置
  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);// 调用了另一个方法
  jboolean success  = (res == e);  // 如果返回的res等于e,则判定满足compare条件(说明res应该为内存中的当前值),但实际上会有ABA的问题
  if (success) // success为true时,说明此时已经交换成功(调用的是最底层的cmpxchg指令)
    update_barrier_set((void*)addr, x); // 每次Reference类型数据写操作时,都会产生一个Write Barrier暂时中断操作,配合垃圾收集器
  return success;
UNSAFE_END

可以看到源码中又调用了另一个原子性的方法:oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);保证其原子性,避免被其它线程插入;到最后会转换成完成CAS功能的原语

参考:

JUC系列第三篇-CAS算法详解

posted @ 2021-04-17 13:26  yhliln  阅读(98)  评论(0编辑  收藏  举报