欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ReentrantLock之Lock方法

程序员文章站 2022-05-05 10:00:13
...

ReentranLock  JDK 1.8 类源码如下:

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;
    ...
    abstract static class Sync extends AbstractQueuedSynchronizer {
      ...
      ...
      /**
       * Performs {@link Lock#lock}. The main reason for subclassing
       * is to allow fast path for nonfair version.
       */
      abstract void lock();

      /**
      * Performs non-fair tryLock.  tryAcquire is implemented in
      * subclasses, but both need nonfair try for trylock method.
      */
      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);
             return true;
         }   
        return false;
      }
     ...
   }
   ...
   /**
 * Sync object for non-fair locks
 */
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    /**
     * Performs lock.  Try immediate barge, backing up to normal
     * acquire on failure.
     */
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

/**
 * Sync object for fair locks
 */
static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}
 ...
}

公平锁和非公平锁都调用了acquire(1);方法,此方法如下:

ReentrantLock之Lock方法

tryAcquire方法如下:如果state状态为0,则获取锁成功,否则(红色框里是重入获取锁的实现,可见是)判断当前线程是否为已获得锁的线程,如果是,则state加1,否则获取失败。

补充:getState是Sync 的父类AbstractQueuedSynchronizer的方法,读者可阅读此源码进一步研究。

ReentrantLock之Lock方法

compareAndSetState(0, 1): CAS 原子性设置(由硬件保证,cpu执行汇编)setExclusiveOwnerThread(Thread.currentThread()) : 设置exclusiveOwnerThread变量/**
 * The current owner of exclusive mode synchronization.
 */
private transient Thread exclusiveOwnerThread;
标记当前获取锁的线程信息。
acquire中调用了addWaiter,此方法如下:

ReentrantLock之Lock方法

可见是将当前线程加入阻塞队列中

所以acquire方法总体执行的是,判断锁的state是否为0,如果是则加锁成功state为1,将当前获取锁的线程标记,否则判断当前获取锁的线程是否为已拿到锁的线程,如果是,state+1 获取锁成功(可重入性);否则,失败,将自己放入队列中(尾插法),执行selfInterrupt();优雅中断(阻塞)。

/**
 * Convenience method to interrupt current thread.
 */
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}

再来看看公平锁和非公平锁的不同:

从源码看,两者在lock中不同在于acquire方法tryAcquire的实现

看源码可知公平锁的实现中多了红框的内容:

ReentrantLock之Lock方法

此端代码是判断当前线程是否为列队头中的线程。。。在阻塞的线程中只有头线程才能获取成功锁