ReentrantLock的实现原理

ReentrantLock是一个显示锁,实现基础都是AQS。所谓的AQS就是AbstractQueuedSynchronizer,

AQS的作用

  • 用来构建锁和同步工具的框架, ReentrantLock、CountDownLatch、Semaphore基础都是AQS
  • AQS有个state变量,是int类型,使用了volatile修饰,AQS围绕state提供两种基本的获取和释放功能

ReentrantLock分析

  • 在ReentrantLock中定义了一个抽象的静态类Sync,该类继承了AbstractQueuedSynchronizer
  • ReentrantLock中还定义了公平锁和非公平锁(FairSync/NonfairSync),这两个锁继承了Sync。
    • 公平锁:线程获取锁的顺序和调用lock的顺序一样,FIFO先进先出
    • 非公平锁:线程锁获取所得顺序和调用lock的顺序无关,随机的
  • ReentrantLock默认是实现非公平锁

非公平锁

/**
  * Creates an instance of {@code ReentrantLock}.
  * This is equivalent to using {@code ReentrantLock(false)}.
  */
 public ReentrantLock() {
        sync = new NonfairSync();
    }
 也同时提供使用公平锁了形参构造器方法来
/**
  * Creates an instance of {@code ReentrantLock} with the
  * given fairness policy.
  * @param fair {@code true} if this lock should use a fair ordering policy
  */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
  • 如何获取锁获取锁
    • ReentrantLock提供lock()方法,该方法直接使用的是Sync类中的lock方法,该方法是个抽象方法,因为ReentrantLock默认是非公平锁,所以lock()方法的具体实现在NonfairSync中的lock()中
final void lock() {
	//判断当前state是否是0,如果是0,则将值设为1,并将当前线程设为独占锁线程
	//否则
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
    	//如果当前state不是0,则当前线程放入等待队列
        acquire(1);
}

//调用AbstractQueuedSynchronized类中的acquire()来中断
public final void acquire(int arg) {
  //调用NonfairSync非公平锁类的tryAcquire()方法
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

//使用addWaiter()方法创建一个Node,同时给一个类型
//将线程加入阻塞队列
//Node.EXCLUSIVE for exclusive, Node.SHARED for shared
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Tail of the wait queue, lazily initialized.  Modified only via method enq to add new wait node.
    // tail是等待队列的尾部,延迟初始化,通过enq()方法添加节点
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //enq方法是一个死循环(是为了保证Node一定能插入队列),当队列为空时,会创建一个空的Node作为head节点
    enq(node);
    return node;
}

//不间断的获取已经在队列中的独占线程
final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

shouldParkAfterFailedAcquire(Node pred, Node node)该方法的作用是检查和更新获取失败的节点的状态。如果线程要阻塞就返回true

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            //如果前一个节点的状态是SIGNAL,阻塞,返回true
            return true;
        if (ws > 0) {
          // 如果前一个节点的状态是CANCELLED,则跳过所有前置任务(通过循环将前面的节点都移除)
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
     		//如果是其他状态,则都将状态更新为SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
final boolean nonfairTryAcquire(int acquires) {
	//获取当前线程
    final Thread current = Thread.currentThread();
    //获得AQS的state是否等于0,等于0表示没有人占有
     int c = getState();
     if (c == 0) {
     	// 然后比较并更新state,如果state是0,就把值设为1
         if (compareAndSetState(0, acquires)) {
         // 当前线程获取锁,并设置线程拥有独占访问权,即获得独占锁
             setExclusiveOwnerThread(current);
             return true;
         }
     }
     //判断当前线程是否是独占锁线程,因为ReentrantLock是可重入的,线程可以不停的lock来增加state的值,对应的就需要unlock来解锁,直到state为0
     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;
}
  • 锁的释放
    • ReentrantLock提供了unlock()方法,该方法中调用了Sync中的release方法。sync.release(1);入参写死为1,因为每当一个线程获取到独占线程时,都会把自己设为head.
public final boolean release(int arg) {
   if (tryRelease(arg)) {
       Node h = head;
       if (h != null && h.waitStatus != 0)
       		//唤醒头节点的下一个节点
           unparkSuccessor(h);
       return true;
   }
   return false;
 }
protected final boolean tryRelease(int releases) {
   int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

你可能感兴趣的:(JAVA-EE)