In depth understanding of Java built-in locks (synchronized) and explicit locks (reentrant lock)
Synchronized and reentrantlock
In multithreaded programming, we use locks when the code needs to be synchronized. Java provides us with two synchronization methods: synchronized and reentrantlock. The explicit lock is jdk1 5. What are the similarities and differences between the two locks? Is there only one option added, or is there another reason? This article will explore for you.
This is the full use of the built-in lock. You've learned it.
The built-in lock is very convenient to use without explicit acquisition and release. Any object can be used as a built-in lock. Using built-in locks can solve most synchronization scenarios. "Any object can be used as a built-in lock" also means that where the synchronized keyword appears, there is an object associated with it. Specifically:
When synchronized acts on a common method, the lock object is this;
When synchronized acts on a static method, the lock object is the class object of the current class;
When synchronized acts on a code block, the lock object is the obj in synchronized (obj).
Explicit lock
The built-in lock is so easy to use, why do you need an explicit lock? Because some things cannot be done with built-in locks, such as:
We want to add a waiting time timeout to the lock. If we give up before we get the lock, we won't wait indefinitely;
We want to obtain the lock in an interruptible way, so that the external thread can send us an interrupt signal to arouse the thread waiting for the lock;
We want to maintain multiple waiting queues for locks, such as a producer queue and a consumer queue, while improving the efficiency of locks.
Explicit locks were formally created to address these flexible requirements. Reentrantlock literally means reentrant lock. Reentrant lock means that a thread can request the same lock multiple times at the same time without causing its own deadlock. The following is the difference between built-in lock and explicit lock:
Timed: renentrantlock Trylock (long timeout, timeunit unit) provides a way to end the waiting at a fixed time. If the thread does not obtain the lock within the specified time, the method will return false and end the thread waiting.
Interruptible: you must have seen interruptedexception. Many methods related to multithreading will throw this exception. This exception is not a burden caused by a defect, but a must, or a good thing. Interruptibility provides us with a way to end the thread in advance (instead of having to wait until the thread ends), which is very useful for canceling time-consuming tasks. For built-in locks, the thread will wait until it can't get the built-in lock, and there is no other way to end the wait except to obtain the lock. Renentrantlock. Lockinterruptibly() It provides us with a way to end the wait with an interrupt.
Condition queue: after a thread obtains a lock, it may enter a waiting state by waiting for a condition to occur (the built-in lock passes the object. Wait() method, and the explicit lock passes the condition. Wait() method) Await () method), the threads entering the waiting state will hang and automatically release the lock, and these threads will be put into the condition queue. Synchronized corresponds to only one conditional queue, while reentrantlock can have multiple conditional queues. What are the benefits of multiple queues? Please look down.
Conditional predicate: after a thread acquires a lock, it sometimes needs to wait for a certain condition to be met before doing anything. For example, the producer needs to wait until the cache is not full to put messages into the queue, while the consumer needs to wait until the cache is not empty to take messages out of the queue. These conditions are called conditional predicates. The thread needs to obtain the lock first, and then judge whether the conditional predicate is satisfied. If it is not satisfied, it will not execute down, and the corresponding thread will give up the execution right and automatically release the lock. Different threads using the same lock may have different conditional predicates. If there is only one conditional queue, when a conditional predicate is satisfied, it is impossible to judge which thread in the wake-up conditional queue; However, if each conditional predicate has a separate conditional queue, when a certain condition is met, we know that the thread on the corresponding queue should be awakened (built-in lock through object. Notify() or object The notifyall() method wakes up, and the explicit lock passes through condition Signal () or condition Signalall() method. This is the benefit of multiple conditional queues.
When using built-in locks, the object itself is both a lock and a condition queue; When an explicit lock is used, the object of renentrantlock is a lock, and the condition queue passes through renentrantlock The newcondition () method is used to obtain multiple condition queues by calling this method multiple times.
A typical example of using explicit locks is as follows:
Note that the above code places unlock () in the finally block, which is necessary. Explicit locks are not automatically released like built-in locks. When using explicit locks, you must manually release them in the finally block. If the lock is not released due to abnormal reasons after obtaining the lock, the lock will never be released! Put unlock () in the finally block to ensure that it can be released normally no matter what happens.
conclusion
Built in locks can solve most scenarios requiring synchronization. Only when additional flexibility is required, explicit locks need to be considered, such as timing, interruptibility, multiple waiting queues and so on.
Although the explicit lock is flexible, it needs to be explicitly applied and released, and the release must be placed in the finally block, otherwise the lock may never be released due to exceptions! This is the most obvious disadvantage of explicit locking.
To sum up, when synchronization is required, give priority to more secure and easy-to-use implicit locks.