7 ReentrantLock bottom layer

Table of Contents

1 tube

2 AQS principle analysis

2.1 Introduction to AQS

2.2 AQS core structure

2.3 AQS two queues

2.3.1 Synchronous waiting queue

2.3.2 Conditional waiting queue

3 ReentrantLock source code

3.1 Fair/Unfair

3.2 Reentrant lock

3.3 Overall process

3.3.1 Locking

3.3.2 Unlocking


1 pipe

Two implementations of monitors in Java:

sychronized: Object Monitor mechanism

AQS: JUC concurrency package Lock implementation

2 AQS principle analysis

2.1 AQS Introduction

The java.util.concurrent package is all about common behaviors, such as: waiting queue, condition queue, exclusive acquisition, shared acquisition, etc.; these are basically provided by AQS (AbstractQueuedSynchronizer)

Lock, Latch, Barrier, etc. are all implemented based on AQS

The inner class Sync inherits AQS

Map the method called by the synchronizer to the corresponding method of Sync

Features of AQS:

blocking wait queue

shared/exclusive

fair/unfair

reentrant

Allow interrupts

2.2 AQS core structure

Resource availability state: volatile int state

getState(); setState(); compareAndSetState()

Two ways to access resources:

Exclusive: only one thread is allowed to execute; ReentrantLock

Share-Sharing: Multiple threads can execute at the same time; Semaphore, CountDownLatch

Main methods:

isHeldExclusively(): Whether the thread is occupying resources exclusively, used in conjunction with condition

tryAcquire(int): Exclusive mode, try to obtain resources

tryRelease(int): exclusive mode, try to release resources

tryAcquireShared(int): Sharing mode, trying to acquire resources; negative number – failure, 0 – success and no remaining resources, positive number – success and remaining resources

tryReleaseShared(int): Sharing mode, try to release resources; true – allow to wake up remaining nodes after release, otherwise false

2.3 AQS two queues

Synchronous waiting queue: Threads that join the queue when acquiring the lock fails

Conditional waiting queue: Release the lock when calling await(), and the thread joins the conditional queue; call signal() to wake up, move the thread from the conditional queue to the synchronization queue, and wait to acquire the lock again.

AQS 5 node status:

0, initialization state, the node is in the sync queue, waiting to acquire the lock

CANCELLED=1, the current thread is canceled

SIGNAL=-1, the threads contained in the successor nodes of the current node need to be run, that is, unpark

CONDITION=-2, the current node is waiting for condition, that is, in the condition queue

PROPAGATE=-3, subsequent acquireShared can be executed in the current scenario

2.3.1 Synchronous waiting queue

1 When the current thread fails to obtain the synchronization status, AQS will encapsulate the current information into a Node, add it to the synchronization queue, and block the current thread.

2 When the synchronization state is released, the first node will be woken up (fair lock) so that it can try to obtain the synchronization state again.

3 signal() or signalAll() transfers the nodes of the condition queue to the synchronization queue (condition queue to synchronization queue)

2.3.2 Conditional waiting queue

Save through one-way linked list and connect using nextWaiter

Call the await() method to block the thread

The current thread is located at the head node of the synchronization queue and calls the await() method to block (the synchronization queue is converted to a conditional queue)

3 ReentrantLock source code

3.1 Fair/Unfair

fair:

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

Unfair:

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

3.2 Reentrant lock

3.3 Overall Process

3.3.1 Lock

After executing the 3.1 lock.lock() method:

Try 3.2 tryAcquire(). If it cannot be obtained, try to join the synchronization queue:

When the current thread cannot obtain the resource, the thread of the head node of the synchronization queue needs to be pulled out to obtain the lock resource.

3.3.2 Unlock

If it is not a reentrant lock, set the current ower thread to empty, setState

Wake up the next node