What is ReentrantLock?
- ReentrantLock is an application implementation based on AQS framework.
- It is a synchronization method of thread concurrent access in JDK. Its function is similar to synchronized. It is a mutual exclusion lock, which can ensure thread safety.
Difference between ReentrantLock and synchronized
- synchronized is the lock implementation of JVM level, and ReentrantLock is the lock implementation of JDK level;
- The synchronized lock status cannot be directly judged in the code, but ReentrantLock can be judged by ReentrantLock#isLocked;
- synchronized is an unfair lock, and ReentrantLock can be fair or unfair;
- synchronized cannot be interrupted, while reentrantlock#lockinterruptable method can be interrupted;
- synchronized will automatically release the lock when an exception occurs, and ReentrantLock requires the developer to display the released lock in the finally block;
- ReentrantLock can obtain locks in many forms: for example, it is more flexible to immediately return the success of tryLock() and wait for the acquisition of a specified length of time;
- synchronized under certain circumstances, for the thread that is already waiting, the subsequent thread obtains the lock first, while ReentrantLock obtains the lock first for the thread that is already waiting;
How ReentrantLock is used
- How to use
//The default parameter is false, which is unfair ReentrantLock lock = new ReentrantLock(); //Fair lock ReentrantLock lock = new ReentrantLock(true); // Lock lock.lock(); try { //Critical zone } finally { // Unlock lock.unlock(); }
- Use example
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Tset1 { // Define data private static int sum = 0; // Define your own lock private static Lock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { // Loop 3 eats and starts three threads for (int i = 0; i < 3; i++) { Thread thread = new Thread(() -> { // Lock lock.lock(); try { // It is less than 30000 after execution without locking for (int j = 0; j < 10000; j++) { sum++; } } finally { // Unlock lock.unlock(); } }); thread.start(); } // Wait for the thread to finish executing Thread.sleep(2000); // Print the final result: 30000 System.out.println(sum); } }
Reentrant mechanism of reentrant lock
- Reduce the process of locking and unlocking, and then improve the performance
import java.util.concurrent.locks.ReentrantLock; import lombok.extern.slf4j.Slf4j; @Slf4j public class Tset2 { public static ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { // The first thread calls second threads, and the second threads call third threads. method1(); } public static void method1() { lock.lock(); try { log.debug("implement method1"); method2(); } finally { lock.unlock(); } } public static void method2() { lock.lock(); try { log.debug("implement method2"); method3(); } finally { lock.unlock(); } } public static void method3() { lock.lock(); try { log.debug("implement method3"); } finally { lock.unlock(); } } }
- results of enforcement
Interruptible mechanism of ReentrantLock (immediate interrupt)
- Application scenario: a class only needs one thread to initialize. After the initialization of other threads, the current thread does not need to continue processing.
import java.util.concurrent.locks.ReentrantLock; import lombok.extern.slf4j.Slf4j; @Slf4j public class Tset3 { public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(() -> { log.debug("t1 start-up..."); // Note: even if the fair lock is set, this method will immediately return the success or failure of obtaining the lock, and the fair policy will not take effect if (!lock.tryLock()) { log.debug("t1 Failed to acquire lock, return immediately false"); return; } try { log.debug("t1 Got the lock"); } finally { lock.unlock(); } }, "t1"); lock.lock(); try { log.debug("main The thread acquired the lock"); t1.start(); // Let thread t1 execute first try { // Simulated service while (true) { } } catch (Exception e) { e.printStackTrace(); } } finally { lock.unlock(); } } }
- results of enforcement
Lock timeout failure mechanism of ReentrantLock
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import lombok.extern.slf4j.Slf4j; @Slf4j public class Tset4 { public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(() -> { log.debug("t1 start-up..."); // overtime try { if (!lock.tryLock(1, TimeUnit.SECONDS)) { log.debug("Wait 1 s Failed to acquire lock after. Return"); return; } } catch (InterruptedException e) { e.printStackTrace(); return; } try { log.debug("t1 Got the lock"); } finally { lock.unlock(); } }, "t1"); lock.lock(); try { log.debug("main The thread acquired the lock"); t1.start(); // Let thread t1 execute first try { // Simulated service while (true) { } } catch (Exception e) { e.printStackTrace(); } } finally { lock.unlock(); } } }
- results of enforcement
Fair lock mode mechanism of ReentrantLock
- new ReentrantLock(true); Wearing a true is a fair lock, and not passing or passing a false is an unfair lock!
import java.util.concurrent.locks.ReentrantLock; import lombok.extern.slf4j.Slf4j; @Slf4j public class Tset5 { public static void main(String[] args) throws InterruptedException { ReentrantLock lock = new ReentrantLock(true); // Fair lock for (int i = 0; i < 500; i++) { new Thread(() -> { lock.lock(); try { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } log.debug(Thread.currentThread().getName() + " running..."); } finally { lock.unlock(); } }, "t" + i).start(); } // Fight for the lock after 1s Thread.sleep(1000); for (int i = 0; i < 500; i++) { new Thread(() -> { lock.lock(); try { log.debug(Thread.currentThread().getName() + " running..."); } finally { lock.unlock(); } }, "Force insertion" + i).start(); } } }
-
Fair lock operation result: execute in the order of entry, log in the normal order, no prominent points, and no screenshots.
-
The result of non queue lock is not fair!
Blocking wake-up mechanism of ReentrantLock
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import lombok.extern.slf4j.Slf4j; @Slf4j public class Tset6 { private static ReentrantLock lock = new ReentrantLock(); private static Condition cigCon = lock.newCondition(); private static boolean hashcig = false; public static void main(String[] args) { // Define the thread that the thread needs to wake up new Thread(() -> { lock.lock(); log.debug("The thread that needs to be awakened is locked"); try { while (!hashcig) { try { log.debug("The thread that needs to be awakened waits!"); cigCon.await(); } catch (Exception e) { e.printStackTrace(); } } log.debug("The thread that needs to be awakened jumps out of the loop!"); } finally { lock.unlock(); } }).start(); // Prepare the thread to wake up new Thread(() -> { lock.lock(); try { // The setting conditions have changed hashcig = true; // Wake up waiting thread cigCon.signal(); } finally { lock.unlock(); } }, "t1").start(); } }
- Operation results
Concluding remarks
- Get more valuable articles and let's become architects together!
- Paying attention to the official account gives you a deep understanding of MySQL.
- Pay attention to official account and keep continuous understanding of concurrent programming every day!
- Pay attention to the official account, and follow the continuous and efficient understanding of spring source code.
- This official account is not advertising!!! Update daily!!!