[concurrent programming] understand various mechanisms of ReentrantLock lock easily

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!!!

Keywords: Concurrent Programming

Added by cesarcesar on Sun, 30 Jan 2022 16:42:18 +0200