浅析AQS中的state属性

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析AQS中的state属性相关的知识,希望对你有一定的参考价值。

分析一下AbstractQueuedSynchronizer的state属性:

/**
 * The synchronization state.
 */
private volatile int state;

ReentrantLock对象加锁时的部分调用栈:

ReentrantLock/lock()

  -> NonfairSync/lock()

    -> AbstractQueuedSynchronizer/acquire()

      -> NonfairSync/tryAcquire()

        -> Sync/nonfairTryAcquire()

// NonfairSync/lock()
final void lock() {
    if (compareAndSetState(0, 1)) //可能存在多线程的竞争,所以用CAS设置,state的初始值为0。
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1); //CAS设置state失败
}

// AbstractQueuedSynchronizer/acquire()
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

// Sync/nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) { 
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc); // 如果是取得锁的线程,再次获取锁,直接使用set方法设置
        return true;
    }
    return false;
}

state属性的总结:
1. 因为存在多线程竞争的情形,使用CAS设置值
2. state初始值为0,线程加一次锁,state加1,获得锁的线程再次加锁,state值再次加1。所以state表示已获得锁线程进行lock操作的次数
3. 是volatile修饰的变量,线程直接从主存中读

 


 

 

接下来研究CAS:

AbstractQueuedSynchronizer/compareAndSetState()

  -> Unsafe/compareAndSwapObject()

    //native方法,进入jvm源码。

    -> unsafe.cpp/Unsafe_CompareAndSwapObject

      -> oop.inline.hpp/oopDesc::atomic_compare_exchange_oop()

        //以linux系统为例,所以查看Linux的实现版本

        -> atomic_linux_x86.inline.hpp/Atomic::cmpxchg_ptr()

          -> atomic_linux_x86.inline.hpp/Atomic::cmpxchg()

// /hotspot/src/share/vm/prims/unsafe.cpp
// These are the methods for 1.8.0
static JNINativeMethod methods_18[] = {
      ...        
      {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z",  FN_PTR(Unsafe_CompareAndSwapObject)}
      ...
};

// /hotspot/src/share/vm/prims/unsafe.cpp
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);
  if (success)
    update_barrier_set((void*)addr, x);
  return success;
UNSAFE_END

// oop.inline.hpp
inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
                                                volatile HeapWord *dest,
                                                oop compare_value,
                                                bool prebarrier) {
  if (UseCompressedOops) {
    if (prebarrier) {
      update_barrier_set_pre((narrowOop*)dest, exchange_value);
    }
    // encode exchange and compare value from oop to T
    narrowOop val = encode_heap_oop(exchange_value);
    narrowOop cmp = encode_heap_oop(compare_value);

    narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
    // decode old from T to oop
    return decode_heap_oop(old);
  } else {
    if (prebarrier) {
      update_barrier_set_pre((oop*)dest, exchange_value);
    }
    return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
  }
}

// atomic_linux_x86.inline.hpp
inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value) {
  return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value);
}

// atomic_linux_x86.inline.hpp
inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
  bool mp = os::is_MP();
  __asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)"
                        : "=a" (exchange_value)
                        : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                        : "cc", "memory");
  return exchange_value;
}

具体的C++代码就不分析了,一次cas没有自旋,在多处理器环境下是需要加锁的。

 

以上是关于浅析AQS中的state属性的主要内容,如果未能解决你的问题,请参考以下文章

AQS源码探究_02 AQS简介及属性分析

AQS简单介绍

AQS原理浅析

面试必死问题:了解Java的AQS吗?

Java并发- CountDownLatchSemaphore与AQS

JUC并发编程 JUC AQS原理 -- AQS概述 & 实现不可重入锁