Java Multithreading (3) -- Lock

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:

  1. The lock() method, which takes control of the lock object, blocks waiting if other threads are occupying the lock
  2. unLock() method, releasing the control of the lock object, must be released, otherwise it will cause deadlock.
  3. 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:

  1. readLock(),, and then you can call lock, unLock, tryLock methods
  2. 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);

Posted by xylex on Tue, 02 Jul 2019 17:06:08 -0700