ReadWriteLock in Java

A ReadWriteLock interface in Java is more sophisticated than the Lock interface. Imagine you have an application that reads from and writes to some resources, but reading frequency is much more higher than writing frequency.

Two or more threads reading the same resource do not cause any problem for each other, i.e., multiple threads reading the same resource are granted access at the same time. But, if a single thread wants to write to the resource then neither reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, ReadWriteLock comes into the picture to rescue.

A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.

ReadWriteLock implementations must guarantee the synchronization of writeLock() operations with respect to the associated readLock(). Thus the synchronization allows a thread successfully acquiring the read lock will see all updates made upon previous release of the write lock.

A read-write lock allows for a greater level of concurrency in accessing shared data and will only be fully realized on a multi-processor.

ReadWriteLock can improve performance and throughput in case that reads are more frequent than writes.

The class ReentrantReadWriteLock is an implementation of ReadWriteLock interface.

Example on Read Write Lock

Here I will show you a basic example on read write lock in Java programming language.

package com.roytuts.java.readwritelock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {

	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		
		Map<String, String> map = new HashMap<>();
		
		ReadWriteLock lock = new ReentrantReadWriteLock();
		
		executorService.submit(() -> {
			lock.writeLock().lock();
			try {
				map.put("site", "https://roytuts.com");
				Thread.sleep(1);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.writeLock().unlock();
			}
		});
		
		Runnable readTask = () -> {
			lock.readLock().lock();
			try {
				System.out.println(map.get("site"));
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.readLock().unlock();
			}
		};
		
		executorService.submit(readTask);
		executorService.submit(readTask);
		
		executorService.shutdown();
	}

}

When you execute the above example you will notice that both read tasks have to wait the whole second until the write task has finished. After the write lock has been released, both read tasks are executed in parallel and print the result simultaneously to the console. They do not have to wait for each other to finish because read-locks can safely be acquired concurrently as long as no write-lock is held by another thread.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *