ReentrantLock- how to achieve an exclusive lock on AQS

1 Overview

ReentrantLock AQS is based on a realization of an exclusive lock , lock fair and unfair lock modes.

The default is to use unfair lock :

    public ReentrantLock() {
        sync = new NonfairSync();
    }
复制代码

You can also specify mode:

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
复制代码
  • 1 ReentrantLockimplements Lockthe interface;
  • 2 ReentrantLockdefines the inner class Sync inherit the AQS: abstract static class Sync extends AbstractQueuedSynchronizer{....};
  • 3 Syncis an abstract class, there are two implementation class NonfairSync/ FairSync, it is used to implement a non-fair lock / fair lock .

Official Example:

class X {
    private final ReentrantLock lock = new ReentrantLock();
    // ...
 
    public void m() {
      lock.lock();  // block until condition holds
      try {
        // ... method body
      } finally {
        lock.unlock()
      }
    }
  }
复制代码

2 implementation

This article only ReentrantLock of lock/unlockimplementation, analysis of how to achieve an exclusive lock on AQS.

The AQS convention (refer AQS core source code analysis and analytical method ):

  • 1 lock: achieve tryAcquire, and called when Lock acquire;
  • 2 unlock: achieve tryRelease, and calls upon UNLOCK release.

2 lock()

ReentrantLock.lock()It calls Sync.lock(), and Sync.lock()is an abstract method, implemented by subclasses.

So NonfairSync/ FairSynctwo classes, necessarily used acquiremethod to acquire lock, and implements tryAcquiremethods.

2.1 NonfairSync

2.1.1 lock

  • 1 to call compareAndSetStatethe state a value from 0 to 1 replacement, successful, indicating that no other thread currently holds the lock, do not line up directly held. By setExclusiveOwnerThreadthe current thread to an exclusive lock holders.
  • Otherwise, by 2 acquireto line up.
        final void lock() {
            if (compareAndSetState(0, 1)) // 如果当前state==0,则说明没有其他线程持有锁,CAS成功。
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
复制代码

2.1.2 tryAcquire

NonfairSync.tryAcquireIt called directly Sync.nonfairTryAcquire.

nonfairTryAcquireNon-fair tryAcquireimplementation, not by AQS.hasQueuedPredecessorsjudges are threads in the queue.

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // state == 0,说明没有其他线程持有锁。
                if (compareAndSetState(0, acquires)) {
                    // 将当前线程设置为`独占锁持有者`,tryAcqire成功。
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                /* 
                如果当前线程正是`独占锁持有者`,叠加state,实现`可重入`,tryAcqire成功。
                也就是说AQS的同步列表中,有多个当前线程的节点。
                */
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
复制代码

2.2 FairSync

2.2.1 lock

Do not compareAndSetStatetry to directly join the queue AQS synchronization of their own.

        final void lock() {
            acquire(1);
        }
复制代码

2.2.2 tryAcquire

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {  // state == 0,说明没有其他线程持有锁。
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    /*
                    `!hasQueuedPredecessors()` 说明AQS的同步队列中,没有比自己更优先的线程在等待
                    */
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                /* 
                如果当前线程正是`独占锁持有者`,叠加state,实现`可重入`,tryAcqire成功。
                也就是说AQS的同步列表中,有多个当前线程的节点。
                */
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
复制代码

FairSync.tryAcquireMore than NonFairSync.tryAcquireone more !hasQueuedPredecessors()judgment, other processes are the same.

3 unlock()

unlock operation NonFairSync/ FairSyncno distinction, directly in the Sync.

SyncThe unlockcall AQS.release, and implemented tryRelease.

public void unlock() {
        sync.release(1);
    }
复制代码

3.1 tryRelease

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            
            // 当前线程不是`独占锁持有者`,抛出异常。
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) { // c == 0 说明锁已经完全释放。
                free = true;
                // 将当前`独占锁持有者`置空。
                setExclusiveOwnerThread(null);
            }
            // 更新state值
            setState(c);
            return free;
        }
复制代码

4 Summary

NonFairSync/ FairSyncThe basic process is the same, except that:

  • 1 NonFairSyncin the lock, will first try compareAndSetState(0, 1)to seize the lock, then it fails acquire(1); FairSyncdirect acquire(1)line.
  • 2 FairSyncat tryAcquirethe time, it is determined compareAndSetState(0, acquires)at the same time, had a plurality hasQueuedPredecessors()of determination, for determining whether a synchronization queue than their priority threads.

Guess you like

Origin juejin.im/post/5dee02c151882512820ada80