This blog post mainly records Reentranctlock internal implementation principles.
Reentrantlock and synchronized are more flexible to use than keywords. How to use Reentranctlock is not much to say, here the main record reentrantlock the internal implementation principle.
First look at the class inheritance structure of Reentrantlock, such as:
There are three internal classes within the Reentrantlock: Sync, Fairsync, Nonfairsync. The source code is as follows:
Sync:
Abstract static class Sync extends Abstractqueuedsynchronizer {private static final long Serialversionuid = 51795 23762034025860L; /** * Performs {@link lock#lock}. The main reason for subclassing * are to allow fast path for Nonfair version. */abstract void lock (); /** * performs Non-fair trylock. Tryacquire is implemented in * subclasses, but both need Nonfair try for Trylock method. */FINAL Boolean nonfairtryacquire (int acquires) {final Thread current = Thread.CurrentThread (); int c = GetState (); if (c = = 0) {if (compareandsetstate (0, acquires)) {Setexclusiveownerthread (current); return true; }} 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; } 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; }
...}
Fairsync:
Static final class Fairsync extends Sync {private static final long serialversionuid = -3000897897090466540l; Final void Lock () {acquire (1); }/** * Fair version of Tryacquire. Don ' t grant access unless * recursive call or no waiters or is first. */Protected Final Boolean tryacquire (int acquires) {final Thread current = Thread.CurrentThread (); int c = GetState (); if (c = = 0) {if (!hasqueuedpredecessors () && compareandsetstate (0, acquires)) { Setexclusiveownerthread (current); return true; }} else if (current = = Getexclusiveownerthread ()) {int NEXTC = c + acquires; if (NEXTC < 0) throw new Error ("Maximum lock count Exceeded"); SetState (NEXTC); return true; } RETUrn false; } }
Nonfairsync:
Static final class Nonfairsync extends Sync { private static final long serialversionuid = 7316153563782823691L; /** * performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void Lock () { if (compareandsetstate (0, 1)) Setexclusiveownerthread (Thread.CurrentThread ()); else acquire (1); } Protected Final Boolean tryacquire (int acquires) { return Nonfairtryacquire (acquires); } }
Fairsync realizes the logic of fair lock logic, Nonfairsync realizes the non-fair lock. Below is the implementation of the most commonly used non-fair locks.
The Nonfairsync.lock () method first sets the state in the AQS based on the CAs and, if true, indicates success, at which point the exclusive thread is set to the current thread. If False is returned, the fetch fails, calling the acquire (1) method. Acquire () method in Aqs, the code is as follows:
Public final void acquire (int arg) { if (!tryacquire (ARG) && acquirequeued (Addwaiter (node.exclusive), ARG)) selfinterrupt (); }
The lock is first acquired again in acquire, and if the acquisition fails, the Addwaiter () method is called to join the current thread to the CHL queue. The CHL queue structure is as follows:
After joining the queue, and then calling Method Acquirequeued (), the code is as follows:
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); } }
In the Acquirequeued () method, first determine if the current node's predecessor node is a header, if it is a head node, then try to acquire the lock and get successful, the current node is set to the head node. Otherwise, determine if the thread that corresponds to the current node hangs, and if the previous node's status is signal, then the current node needs to be suspended. Call the Parkandcheckinterrupt () method to suspend the thread of the current node.
The lock () logic above is a non-fair lock, a fair lock and an unfair lock, the difference is basically a fair lock before acquiring, the first need to determine whether there is a predecessor node, if there is a predecessor node, you need to wait. We see the Tryacquire () method in Fairsync, which first calls the Hasqueuedpredecessors () method to determine if there is a predecessor node.
The Reentrantlock of Java Learning