一、引题
  今天在写一个无锁队列的小项目时用到了 Java Unsafe 包中的 compareAndSwapObject 方法,也就是比较并交换 Java Object ,对于这个方法以前都仅是停留在使用阶段,对底层源码的探究比较少,所以今天就打开源码探究一下该方法的底层到底是怎样实现的,其方法中的这个比较对于 Java Object 来说到底比较的是什么?


二、源码探究
2.1 Java API
  /***
   * Compares the value of the object field at the specified offset
   * in the supplied object with the given expected value, and updates
   * it if they match.  The operation of this method should be atomic,
   * thus providing an uninterruptible way of updating an object field.
   *
   * @param obj the object containing the field to modify.
   * @param offset the offset of the object field within <code>obj</code>.
   * @param expect the expected value of the field.
   * @param update the new value of the field if it equals <code>expect</code>.
   * @return true if the field was changed.
   */
  public native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);

  对于 CAS 系列方法的具体使用方法就不在这里赘述了,我们都知道该方法的作用是原子操作比较并交换两个值,运用的时底层硬件所提供的 CAS 支持,在 Java API 中我们可以看到该方法具有四个参数。

obj :包含要修改的字段对象;
offset :字段在对象内的偏移量;
expect : 字段的期望值;
update :如果该字段的值等于字段的期望值,用于更新字段的新值;
  同时我们注意到这是一个本地方法,底层是使用 C++ 来实现的,因此我们直接跟进本地方法中。

2.2 C++ API
// Unsafe.h
virtual jboolean compareAndSwapObject(::java::lang::Object *, jlong, ::java::lang::Object *, ::java::lang::Object *);

// natUnsafe.cc
static inline bool
compareAndSwap (volatile jobject *addr, jobject old, jobject new_val)
{
    jboolean result = false;
    spinlock lock;
  
      // 如果字段的地址与期望的地址相等则将字段的地址更新
    if ((result = (*addr == old)))
        *addr = new_val;
    return result;
}

// natUnsafe.cc
jboolean
sun::misc::Unsafe::compareAndSwapObject (jobject obj, jlong offset,
                     jobject expect, jobject update)
{
    // 获取字段地址并转换为字符串
    jobject *addr = (jobject*)((char *) obj + offset);
    // 调用 compareAndSwap 方法进行比较
    return compareAndSwap (addr, expect, update);
}

  底层的实现也比较简单,总结来说:

通过我们传入的字段在对象中的偏移量来获取到字段的地址(对象首地址 + 字段在对象中的偏移量);
然后调用 CompareAndSwap 方法比较字段的地址是否与我们期望的地址相等,如果相等则使用我们传入的新地址更新字段的地址;

三、内容总结
  所以最后我们可以得出结论:compareAndSwapObject 方法其实比较的就是两个 Java Object 的地址,如果相等则将新的地址(Java Object)赋给该字段。
 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐