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