Lock principle

Lock

synchronized limitations: When a thread attempts to acquire a lock, the lock will be less than if the acquisition has been blocked. If you get a lock thread goes to sleep or blocked, unless the current thread exception, otherwise the other thread tries to acquire the lock must have been waiting for. This time we need to use Lock.

AQS

AbstractQueuedSynchronizer referred AQS, is used to build a container frame lock and synchronization. In fact many of the classes are based on concurrent package AQS construct, e.g. ReentrantLock, Semaphore, CountDownLatch, ReentrantReadWriteLock, FutureTask like. AQS solve a lot of the details in the synchronized container design.

AQS using a FIFO queue represents a queue of threads waiting for the lock, queue head node called "sentinel node" or "dumb node", it is not associated with any thread. Other nodes associated with waiting threads, each node maintains a waiting state waitStatus. FIG
Here Insert Picture Description
AQS There is also a field indicating the status of State , for example, it represents a ReentrantLocky number reentrant thread lock , Semaphore with which represents the remaining number of licenses, FutureTask task represented by its state. Updates the state variable values are used to ensure the operation of CAS atomic update operation.

ReentrantLock internal structure

The default implementation of non-equity ReentrantLock lock, but also can be set to lock fair.

AbstractQueuedSynchronizer inherited AbstractOwnableSynchronizer, this class has only one variable: exclusiveOwnerThread , represents the lock thread is currently occupied , and provides the corresponding get, set method.

ReentrantLock internal structure:
Here Insert Picture Description

step

The steps outlined below:

  1. CAS attempt to obtain a lock, to determine whether the state is 0 (representing the current lock is not occupied), if it is set to 0 put 1. And setting the current thread for thread exclusive lock, showing the lock acquisition success.
  2. Attempt to acquire the lock. Failed to get the thread attempts to acquire again, check the state field, if it is 0, indicating that the lock is not occupied, then try to occupy, if not zero, check the current lock is occupied themselves, if they themselves occupied, the update state field indicating re-enter the number of locks.
  3. Into the team. If you still get fails, enqueue operation. In the queue has not been initialized, tail == null, so there will be a combination of thread + CAS nonblocking atomic operation by classical spin, the final initialization queue. Other threads also into the team.
  4. Hang. B and C are performed successively acquireQueued (final Node node, int arg). This approach has let the team into the thread tries to acquire the lock, if the failure will be suspended. After the thread into the team can hang on the premise that the state of its predecessor node is SIGNAL, its meaning is "Hi, in front of the brothers, and if you get locked out of the team, remember to wake me!."
  5. Whether to try to release the lock, if the release succeeds, then view the head node status is SIGNAL, the next node is associated with the thread wakes up if the head node.

step 1

First, the operation with a CAS, it is determined whether the state is 0 (indicating the current lock is not occupied), if 0 is set to 1 put it, and set an exclusive lock for the thread of the current thread, showing the lock acquisition success. When multiple threads simultaneously try to occupy the same lock, CAS operation can only guarantee a successful operation thread, leaving only to go obediently line up.

Note: The "unfair" that is reflected here, if just holding the lock thread releases the lock, state set to 0, while waiting in line locks the threads have not awakened, the new thread directly to seize the lock, then " jump the queue "the.

Step 2

If the current thread to compete with three locks, suppose thread A CAS operation was successful, and happy to get a lock of return, then thread B and C is set failed state, else went inside. We look acquire down.

Attempt to acquire a lock. Check the state field, if it is 0, indicating that the lock is not occupied, then try to occupy, if not zero, check the current lock is occupied themselves, if they themselves occupied, the update state field indicates the number of re-entry lock. If the above points have not been successful, then acquire the lock fails, it returns false. If you attempt to acquire a lock is successful, the method returns directly.

Step 3

Into the team. Since in the above-mentioned A thread lock already occupied, so the B and C perform tryAcquire failed, and the wait queue. If the thread holding the lock A dead link, then B and C will be suspended. B, C threads attempt queues, and the queue has not been initialized, tail == null, it will come to have a thread at least enq (node). We assume the same time come to enq (node) in. It embodied classical spin + CAS combination thereof non-blocking atomic operation. Due to the use of the CAS achieve compareAndSetHead class provides operating unsafe, so only one thread creates a head node successfully. Suppose successful thread B, then B, C to start the second round of the cycle, when tail no longer empty, else go inside both threads. Assuming that B thread compareAndSetTail successful, then you can return to the B, C due to the failure of the team also need a third round of circulation. Eventually all the threads can be successfully into the team.

When the B, C into the queue, then the queue AQS follows:
Here Insert Picture Description
Step 4

Hang. B and C are performed successively acquireQueued (final Node node, int arg ). This approach has let the team into the thread tries to acquire the lock, if the failure will be suspended.
After the thread into the team can hang on the premise that the state of its predecessor node is SIGNAL, its meaning is "Hi, in front of the brothers, and if you get locked out of the team, remember to wake me!." So shouldParkAfterFailedAcquire will first determine whether the current node precursor state to meet the requirements, if they meet the return true, then call parkAndCheckInterrupt, will hang themselves. If not, look precursor node is> 0 (CANCELLED), if you traverse forward until the first to meet the requirements of the precursor, if not the precursor node status will be set to SIGNAL. Throughout the process, if the state is not the precursor node SIGNAL, then your own peace of mind can not be suspended, pending the need to find a reassuring point, at the same time you can try to see if there is no chance to try to compete lock.
Here Insert Picture Description
Step 5

tryRelease process as follows: if the current thread releases the lock holding a lock, an exception is thrown. If holding the lock, release the state calculated value is 0, if 0 indicates that the lock has been successfully released, and then empty the exclusive thread, last updated state value, returning free.

If the release is successful, view the head node status is SIGNAL, if it is associated with the next node is the first node of the thread wakes up, so if the release failed to return false to unlock failure. Here we also found out that each time only evoke node associated with the first node of the next thread.

Fair locks

Different fair and unfair lock lock in that equity to acquire the lock when the lock will not go to check the state status, but directly execute aqcuire (1), no further explanation.

  • Timeout mechanism
  • CLH queue lock

https://blog.csdn.net/qq_33945246/article/details/104037001

https://www.jb51.net/article/105762.htm

Published 67 original articles · won praise 32 · views 60000 +

Guess you like

Origin blog.csdn.net/weixin_43751710/article/details/105080610