1. ReentrantLock Reentry Lock
ReentrantLock is the implementation class of Lock interface. ReentrantLock provides a more flexible mechanism than synchronized. It has the following advantages:
- When using synchronized keywords, you can only use wait(), notify() and other access and release controls in the synchronized block structure. With Lock, acquisition and release may not be in the same block structure.
- The Lock interface provides the tryLock() method, which attempts to acquire the lock, returns false if it has been acquired by other threads, and continues to execute the code without blocking the wait as synchronized.
- Lock performs better than synchronized
public class Test { public static void main(String[] args) { PrintQueue printQueue = new PrintQueue(); for (int i = 0; i < 10; i++) { new Thread(new Job(printQueue)).start(); } } } class PrintQueue{ //Declare the lock object and initialize it private final Lock queueLock = new ReentrantLock(); public void printJob(Object document){ //Control of acquiring lock object queueLock.lock(); Long duration = (long)(Math.random()*10000); System.out.println(duration); try { Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { //Control of Release Lock Object queueLock.unlock(); } } } class Job implements Runnable{ private PrintQueue printQueue; public Job(PrintQueue printQueue){ this.printQueue = printQueue; } @Override public void run() { printQueue.printJob(new Object()); } }
The three main methods of Lock interface are:
- The lock() method, which takes control of the lock object, blocks waiting if other threads are occupying the lock
- unLock() method, releasing the control of the lock object, must be released, otherwise it will cause deadlock.
- tryLock() method, try to get the lock, if the current other thread is occupying the lock, will not block the wait and will immediately return false
2. ReentrantReadWirteLock Reentry Read-Write Lock
ReentrantReadWirteLock is the implementation class of ReadWriteLock interface. This class has two locks, one is read operation lock and the other is write operation lock.
- It allows multiple threads to access simultaneously when using read operation locks, but only one thread is allowed when using write operation locks.
- When a thread performs write operations, other threads cannot read operations.
The separation of read and write greatly improves the efficiency of the program compared with synchronized.
There are two main ways to use ReentrantReadWriteLock:
- readLock(),, and then you can call lock, unLock, tryLock methods
- writeLock(), and then you can call lock, unLock, tryLock methods
class PricesInfo{ private double price1; private double price2; //Read-write lock private ReadWriteLock readWriteLock; public PricesInfo(){ price1 = 1.0; price2 = 1.0; readWriteLock = new ReentrantReadWriteLock(); } /** * Get read locks to get data * @return */ public double getPrice1(){ //Getting Read Locks readWriteLock.readLock().lock(); double value = price1; //Release read lock readWriteLock.readLock().unlock(); return value; } public double getPrice2(){ readWriteLock.readLock().lock(); double value = price2; readWriteLock.readLock().unlock(); return value; } public void setPrices(double price1,double price2){ //Getting Write Locks readWriteLock.writeLock().lock(); this.price1 = price1; this.price2 = price2; //Release Write Lock readWriteLock.writeLock().unlock(); } }
3. Fairness of Lock
Both ReentrantLock and ReentrantReadWriteLock classes have a boolean parameter fair with a default value of false.
When fair = false, it is "unfair mode", and if there are multiple threads waiting for the lock, the lock will randomly select one of them.
When fair = true, it is "fair mode", and if there are multiple threads waiting for the lock, the lock will choose the thread with the longest waiting time.
To modify fair values, just use overloaded constructors:
private Lock queueLock = new ReentrantLock(true);