ReadWriteLock in Java



ReadWriteLock

This tutorial covers about ReadWriteLock in Java, its methods, and how to implement it using a detailed example.

ReadWriteLock in Java

Java ReadWriteLock

ReadWriteLock is an interface in Java that is part of the java.util.concurrent.locks package. It is an advanced lock mechanism that allows multiple threads to read a shared resource but only one thread to write a shared resource. It supports multithreading without causing concurrency issues.

We need to follow the below rules to implement ReadWriteLock in Java to avoid concurrency errors.

ReadLock: Allows multiple threads to read the same resource and there is no thread requesting or having write-lock on it.

WriteLock: Allows only one thread to acquire write-lock and there is no thread having a read lock on the same resource.

Java ReadWriteLock implementation class

The ReentrantReadWriteLock class implements the ReadWriteLock interface.

ReadWriteLock rl = new ReentrantReadWriteLock();

Methods of Java ReadWriteLock interface

Lock readLock()

We can use this lock to acquire read-lock access on the shared resource. Using the readLock().lock() method we can lock the shared resource for reading. After reading the resource, we can release the lock using the readLock().unlock() method.

ReadWriteLock rl = new ReentrantReadWriteLock();
rl.readLock().lock();
try {
  //code
}
finally {
  rl.readLock().unlock();
}

Lock writeLock()

We can use this lock to acquire write-lock access on the shared resource. Using the writeLock().lock() method we can lock the shared resource for writing. After performing the required action, we can release the lock using the writeLock().unlock() method.

ReadWriteLock rl = new ReentrantReadWriteLock();
rl.writeLock().lock();
try {
  //code
}
finally {
  rl.writeLock().unlock();
}

ReadWriteLock example

Now, let us see how we can use the ReadWriteLock interface and its methods using a simple example. We have 2 methods addElements() to add elements to the list and getElements() to get the element at the specified index. While adding the elements to the list, we acquire a writeLock since we are writing it. Similarly for retrieving the element, we use the readLock since we are reading the data.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
  
  private final ReadWriteLock rwl = new ReentrantReadWriteLock();
  private final Lock wl = rwl.writeLock();
  private final Lock rl = rwl.readLock();
  
  private final List<String> list = new ArrayList<String>();

  public static void main(String[] args) {
    ReadWriteLockDemo d = new ReadWriteLockDemo();
    d.addElements("Java");
    d.addElements("Python");
    d.addElements("Perl");
    
    System.out.println("Printing element in main thread: " + d.getElements(1));
  }
  
  public void addElements(String s) {
    wl.lock();
    
    try {
      list.add(s);
      System.out.println("Element " + s + " is added to the list");
    }
    finally {
      wl.unlock();
    }
  }
  
  public String getElements(int i) {
    rl.lock();
    
    try {
      System.out.println("Retrieve element at index " + i + ": " + list.get(i));
      return list.get(i);
    }
    finally {
      rl.unlock();
    }
  }

}
Element Java is added to the

list

Element Python is added to the list
Element Perl is added to the list
Retrieve element at index 1: Python
Printing element in main thread: Python

Now let us see a different example where we use the multithreading concept to describe the synchronization using the Java ReadWriteLock.

In this example, we create 2 threads for Read class and 1 thread each for WriteOdd and WriteEven class. The Read class only reads the String value “val”. The WriteOdd class writes the odd number whereas the WriteEven class writes the even number.

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {

  private static final ReadWriteLock rwl = new ReentrantReadWriteLock(true);
  private static String val = "1";
  
  public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new Read(),"ReadThread1");
    Thread t2 = new Thread(new Read(),"ReadThread2");
    Thread t3 = new Thread(new WriteOdd(),"Write odd");
    Thread t4 = new Thread(new WriteEven(),"Write even");
    
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    
    t1.join();
    t2.join();
    t3.join();
    t4.join();
  }
  
  static class Read implements Runnable {

    @Override
    public void run() {
      for(int i=1;i<=3;i++) {
        rwl.readLock().lock();
        System.out.println(Thread.currentThread().getName() + " --- Value: " + val);
        rwl.readLock().unlock();
      }
      
    }
    
  }

  static class WriteOdd implements Runnable {

    @Override
    public void run() {
      for(int i=1;i<=5;i+=2) {
        try {
          rwl.writeLock().lock();
          System.out.println("Writing Odd number");
          val = val.concat(" " + i);
        }
        finally {
          rwl.writeLock().unlock();
        }
      }
      
    }
    
  }
  
  static class WriteEven implements Runnable {

    @Override
    public void run() {
      for(int i=2;i<=6;i+=2) {
        try {
          rwl.writeLock().lock();
          System.out.println("Writing even number");
          val = val.concat(" " + i);
        }
        finally {
          rwl.writeLock().unlock();
        }
      }
      
    }
    
  }
}

Writing Odd number
ReadThread2 --- Value: 1 1
Writing even number
ReadThread1 --- Value: 1 1 2
Writing Odd number
Writing even number
ReadThread2 --- Value: 1 1 2 3 4
ReadThread1 --- Value: 1 1 2 3 4
Writing Odd number
Writing even number
ReadThread2 --- Value: 1 1 2 3 4 5 6
ReadThread1 --- Value: 1 1 2 3 4 5 6

You might also like to read Deadlock in Java

Reference