The Spring Festival is approaching, and the epidemic is getting more and more serious, but lian can’t stop the urge to bring his family back home (Hubei) to reunite. In response to the state’s request, we went for nucleic acid testing.
An exclusive lock
In the morning, Lian took a family of three to nanjing First Hospital for nucleic acid testing. The nurse sister stood at the door of the hospital and told us that there were many people, both adults and children, who needed to queue up one by one to wait for the doctor to collect saliva test. OK, let’s use the code + figure to see how our family of three queued up!
import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author: jiaolian * @date: Created in 2021-01-22 10:33 * @description: Created in 2021-01-22 10:33 * @description: Created in 2021-01-22 10:33 */ public class ExclusiveLockTest {private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); // private static class Hospital {private String name; public Hospital(String name) { this.name = name; } public void checkUp() {try {writelock.lock (); System.out.println(thread.currentThread ().getName()+" doing DNA testing "); // The nucleic acid process... Sad... Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { writeLock.unlock(); }} public static void main(String[] args) throws InterruptedException {Hospital Hospital = new Hospital(" Hospital "); Threadjlwife = new Thread(()-> hospital.checkup ()); JLWife.start(); Thread.sleep(100); JLSon = new Thread(()-> hospital.checkup ()); JLSon.start(); Thread.sleep(100); JL = new Thread(()-> hospital.checkup ()); JL.start(); }}Copy the code
As the code above: in the main thread start three threads to queue up at the hospital door, lady first, called practice wife is the first row, the middle station is called practice children, finally is called practice themselves. Let’s say we simulated a nucleic acid test that takes 3 seconds. We used an exclusive lock in the code, which can be understood as there is only one doctor in the hospital, and one doctor can only do nucleic acid for one person at a time, so we need to queue up for testing one by one. Therefore, it takes a total of 9 seconds to complete the code execution, and all nucleic acid tests can be completed. The code logic is relatively simple, as in our previous article describing synchronized. Nucleic acid queuing let’s use a picture to describe it!
AQS stands for AbstractQueueSynchroniz, which means queue synchronizer. In essence, AQS is a bidirectional linked list, in which each thread is encapsulated into a Node Node, and each Node is added by tail insertion. In addition, the Node also encapsulates state information, such as whether it is exclusive or shared. The above case represents the exclusive Node. The doctor itself is a shared resource, which is called state inside AQS and represented by int type. If a thread grabs the lock, it will increment, and any thread that does not grab the lock will block waiting for an opportunity to wake up. Figure below: Abstract the internal structure of AQS according to our understanding.
** ****AQS is a two-way linked list that uses Node to wrap threads, and then connects them in a first-come, first-come manner (except for unfair locking). The unfair lock was described by a simple example in the case of queuing for lunch that I wrote earlier. Interested in children’s shoes can be turned over! 支那
A Shared lock
The nucleic acid process above is performed synchronously, called exclusive lock. So what does shared lock mean? Now called practice children only 3 years old, can not independently complete the nucleic acid test, the nurse sister empathy, observation is called practice son is in line behind the wife, let them do nucleic acid test at the same time. This simultaneous operation of nucleic acid is equivalent to simultaneous access to doctor resources, which we call shared lock. Here is our test code.
import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author: jiaolian * @date: Created in 2021-01-21 19:54 * @description: Created in 2021-01-21 19:54 */ public class SharedLockTest {private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private static ReentrantReadWriteLock.ReadLock readLock = lock.readLock(); // private static class Hospital {private String name; public Hospital(String name) { this.name = name; } public void checkUp() {try {readlock. lock(); System.out.println(thread.currentThread ().getName()+" doing DNA testing "); // The nucleic acid process... Sad... Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { readLock.unlock(); }} public static void main(String[] args) throws InterruptedException {Hospital Hospital = new Hospital(" Hospital "); Threadjlwife = new Thread(()-> hospital.checkup ()); JLWife.start(); Thread.sleep(100); JLSon = new Thread(()-> hospital.checkup ()); JLSon.start(); /*Thread.sleep(100); JL = new Thread(()-> hospital.checkup ()); JL.start(); * /}}Copy the code
. We use the above code ReentrantReadWriteLock ReadLock as read lock, in the main thread startup “call practice wife” and “practice” two threads, had a total of both mother and son takes 6 seconds to complete, now can be done only need 3 seconds, the Shared lock advantage is higher efficiency. The following figure shows the Node status at a certain time in AQS. Compare the above image, the Node state has changed to share, these nodes can share doctor resources at the same time!
Synchronized locks do not respond to interrupts
/** * @author: jiaolian * @date: Created in 2020-12-31 18:17 * @description: sync does not respond to interrupts * @modified By: Practice * * public: call/public class SynchronizedInterrputedTest {private static class MyService {public synchronized void LockInterrupt () {try {system.out.println (thread.currentThread ().getName()+" lock "); while (true) { //System.out.println(); } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { MyService myService = new MyService(); ThreadA = new Thread(()->{myService.lockinterrupt (); myService.lockinterrupt (); }); threadA.start(); Thread.sleep(1000); Start thread B, interrupt, synchronized does not respond interrupt! Thread threadB = new Thread(()->{ myService.lockInterrupt(); }); threadB.start(); Thread.sleep(1000); threadB.interrupt(); }}Copy the code
As the above code: start thread A first, let thread A have the lock first, sleep for 1 second and then start thread B, let thread B be in the runnable state, interrupt thread B after 1 second. The output on the console is as follows: Thread A obtains the lock, but the console does not immediately output an error message after waiting for 2 seconds, and the program has not finished executing, indicating that synchronized**** lock does not respond to interruption, and only after thread B obtains the lock will output an error message of thread interruption!
AQS response interrupted
Lock provides both Lock and lockInterruptibly. The Lock method and synchronized method do not respond to interrupts. Let’s use nucleic acid as an example.
import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author: jiaolian * @date: Created in 2021-01-22 15:18 * @description: AQS response interrupt code test * @modified By: Public class AQSInterrputedTest {private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); // private static class Hospital {private String name; public Hospital(String name) { this.name = name; } / / nucleic acid detection line test public void checkups () {try {writeLock. LockInterruptibly (); System.out.println(thread.currentThread ().getName()+" doing DNA testing "); // The nucleic acid process... Sad... Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { writeLock.unlock(); }} public static void main(String[] args) throws InterruptedException {Hospital Hospital = new Hospital(" Hospital "); Threadjlwife = new Thread(()-> hospital.checkup ()); JLWife.start(); Thread.sleep(100); JLSon = new Thread(()-> hospital.checkup ()); JLSon.start(); Thread.sleep(100); JL = new Thread(()-> hospital.checkup ()); JL.start(); System.out.println(" nurse wants to chat with nurse!") // Wait 1 second, interrupt call thread system.out. println(" nurse little sister want to chat with nurse! ); Thread.sleep(1000); JL.interrupt(); }}Copy the code
As above code: called practice a family of three using an exclusive lock queue to do nucleic acid, called practice thread wait for a second, the nurse sister wants to and called practice private chat! Is it possible that the little sister will have any idea, so called practice immediately interrupted the nucleic acid test, attention is immediately interrupted. The console print results are as follows: call practice wife thread and call practice child thread have done nucleic acid, but call practice did not succeed! Because it was interrupted by the nurse sister, the result is shown in the picture below. So we can conclude that locks can respond to interrupts in AQS. Now what happens if I change the lockInterruptibly method to lock. If I change the lockInterruptibly method to lock, MY sister calls me again and asks me if I have to successfully obtain the lock. Encounter with such a thing, can only say little sister is intentional, little sister is too bad. The lock method does not respond to interrupt tests you can test yourself. Let’s see if I’ve wronged the nurse.
We can draw a conclusion: in AQS, if a thread is acquiring the lock or is in the waiting state and another thread interrupts the thread, the response interrupt means that the thread interrupts immediately, while the non-response interrupt means that the thread needs to acquire the lock and then interrupts.
Conditions of the queue
Life may be a little rough. A long one hour queue waiting finally past, it is our turn to prepare to do nucleic acid, you say not spirit, every time call practice wife go out all take ID card, but just go home this forget? Let’s use the code to see what happened in the process of doing nucleic acid. And how to deal with it!
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author: jiaolian * @date: Created in 2021-01-22 16:10 * @description: Conditional queue test * @modified By: Public class ConditionTest {private static ReentrantReadWriteLock lock = new treadwritelock (); private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); Private static Condition Condition = writeLock. NewCondition (); // private static class Hospital {private String name; public Hospital(String name) { this.name = name; } public void checkUp(Boolean isIdCard) {try {writelock.lock (); validateIdCard(isIdCard); System.out.println(thread.currentThread ().getName()+" doing DNA testing "); // The nucleic acid process... Sad... Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { writeLock.unlock(); System.out.println(thread.currentThread ().getName()+" test completed "); }} // Verify identity information; Private void validateIdCard(Boolean isIdCard) {// If there is no id, wait for if (! IsIdCard) {try {system.out.println (thread.currentThread ().getName()+" "); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); Public void singleAll() {try {writelock.lock (); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { writeLock.unlock(); }} public static void main(String[] args) throws InterruptedException {Hospital Hospital = new Hospital(" Hospital "); Thread.currentthread ().setName(" nurse Thread "); Thread JLWife = new Thread(()->{ hospital.checkUp(false); }," call practice wife "); JLWife.start(); Thread.sleep(100); JLSon = new Thread(()-> hospital.checkup (true)); JLSon.start(); Thread.sleep(100); Thread JL = new Thread(()->{ hospital.checkUp(true); }, "lian"); JL.start(); Jl.join (); hospital.singleAll(); }}Copy the code
As above code: a family for exclusive lock need to queue detection, called practice wife advanced to prepare nucleic acid, nurse sister said to brush id card to go in, called practice wife suddenly recalled, go out to forget to take id card, this can do, need to queue again? Call practice wife is very panic, nurse little sister said, or so, you hurry home to take, such as called practice, called practice first test, I hurriedly arrange you to go in to do nucleic acid, so you don’t need to queue up again, this is the expression of this code. Let’s take a look at the execution results as shown below, which are consistent with our analysis results. The place circled in red at the end of the figure is called Lian’s wife and the nucleic acid test is finally completed. Let’s take a look at the internal process at AQS.
Below, when called to practice his wife first acquiring a lock, found id forgot to take my call await method will release hold the lock, and put himself as node to node in the conditions of the end of the queue, the conditions of the queue is empty, so the condition of the queue only practice wife called a thread on the inside, then the doctor nurse will little sister nucleic acid under the resources allocated to release a wait, Locksupport. unpark is used to wake up the handler, which is equivalent to wait/notify/notifyAll in the basic series. When the execution of the call thread is completed and there is no thread behind it, the nurse calls the singleAll method to wake up the call thread of the conditional queue, and joins the tail of the AQS, waiting for execution. Where the conditional queue is a one-way linked list, an AQS can correspond to multiple conditional queues via newCondition(). We’re not going to test it in code alone.
conclusion
Today, we use the way code + + picture story illustrates the AQS several important concepts, sorting out hope to be able to help you, write more than is not complete, there are many need to change at the same time, hope dear friends to correct and review, output years ago this time will continue to implement AQS advanced lock, such as: already, thread pool of these concepts, etc. Please like and follow the last one. My name is Lian [public number], while calling while practicing.
Note: this story is made up of their own, only for your reference. I wish you all a smooth reunion!