Java Concurrency with ReadWriteLock

Writing multithreaded java applications is not a piece of cake. Extra care must be taken because bad synchronization can bring your application to its knees. The JVM heap is shared by all the threads. If multiple threads need to use the same objects or static class variables concurrently, thread access to shared data must be carefuly managed. Since version 1.5, utility classes commonly useful in concurrent programming is included in the JSDK.

In Java synchronized keyword is used to acquire a exclusive lock on an object. When a thread acquires a lock of an object either for reading or writing, other threads must wait until the lock on that object is released. Think of a scenerio that there are many reader threads that reads a shared data frequently and only one writer thread that updates shared data. It’s not necessary to exclusively lock access to shared data while reading because multiple read operations can be done in parallel unless there is a write operation.

In this post i’ll give an example usage of ReadWriteLock interface which is introduced in the Java 1.5 API Doc. In Java Api Documentation it says :

 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.

Reader threads can read shared data simultaneously. A read operation does not block other read operations. This is the case when you execute an SQL SELECT statement. But write operation is exclusive. This means all readers and other writers are blocked when a writer thread holds the lock for modifing shared data.

Writer.java This class represents a thread that updates shared data. Writer uses WriteLock of ReadWriteLock to exclusively lock access to dictionary.

package deneme.readwritelock;
 
 
 public class Writer extends Thread{
   private boolean runForestRun = true;
   private Dictionary dictionary = null;
   
   public Writer(Dictionary d, String threadName) {
     this.dictionary = d;
     this.setName(threadName);
   }
   @Override
   public void run() {
     while (this.runForestRun) { 
       String [] keys = dictionary.getKeys();
       for (String key : keys) {
         String newValue = getNewValueFromDatastore(key);
         //updating dictionary with WRITE LOCK
         dictionary.set(key, newValue);
       }
       
       //update every seconds
       try {
         Thread.sleep(1000);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
     }
   }
   public void stopWriter(){
     this.runForestRun = false;
     this.interrupt();
   }
   public String getNewValueFromDatastore(String key){
     //This part is not implemented. Out of scope of this artile
     return "newValue";
   }
 }

Reader.java This class represents a thread that reads share data.

package deneme.readwritelock;
 
 public class Reader extends Thread{
   
   private Dictionary dictionary = null;
   public Reader(Dictionary d, String threadName) {
     this.dictionary = d;
     this.setName(threadName);
   }
   
   private boolean runForestRun = true;
   @Override
   public void run() {
     while (runForestRun) {
       String [] keys = dictionary.getKeys();
       for (String key : keys) {
         //reading from dictionary with READ LOCK
         String value = dictionary.get(key);
         
         //make what ever you want with the value.
         System.out.println(key + " : " + value);
       }
       
       //update every seconds
       try {
         Thread.sleep(1000);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
     }
   }
   
   public void stopReader(){
     this.runForestRun = false;
     this.interrupt();
   }
 }

Dictionary.java This is a simple and thread safe dictionary. Read operations are managed through ReadLock and write operations (updates) are managed throuh WriteLock.

package deneme.readwritelock;
 
 import java.util.HashMap;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 public class Dictionary {
   
   private final ReentrantReadWriteLock readWriteLock = 
     new ReentrantReadWriteLock();
 
   private final Lock read  = readWriteLock.readLock();
   
   private final Lock write = readWriteLock.writeLock();
   
   private HashMap<String, String> dictionary = new HashMap<String, String>();
   
   public void set(String key, String value) {
     write.lock();
     try {
       dictionary.put(key, value);
     } finally {
       write.unlock();
     }
   }
   
   public String get(String key) {
     read.lock();
     try{
       return dictionary.get(key);
     } finally {
       read.unlock();
     }
   }
 
   public String[] getKeys(){
     read.lock();
     try{
       String keys[] = new String[dictionary.size()];
       return dictionary.keySet().toArray(keys);
     } finally {
       read.unlock();
     }
   }
   
   public static void main(String[] args) {
     Dictionary dictionary = new Dictionary();
     dictionary.set("java",  "object oriented");
     dictionary.set("linux", "rulez");
     Writer writer  = new Writer(dictionary, "Mr. Writer");
     Reader reader1 = new Reader(dictionary ,"Mrs Reader 1");
     Reader reader2 = new Reader(dictionary ,"Mrs Reader 2");
     Reader reader3 = new Reader(dictionary ,"Mrs Reader 3");
     Reader reader4 = new Reader(dictionary ,"Mrs Reader 4");
     Reader reader5 = new Reader(dictionary ,"Mrs Reader 5");
     writer.start();
     reader1.start();
     reader2.start();
     reader3.start();
     reader4.start();
     reader5.start();
   }
   
 }

Reference: ReadWriteLock example in Java from our JCG partner Ilkin Ulas at the All your base are belong to us blog.

Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


9 × two =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books
Get tutored by the Geeks! JCG Academy is a fact... Join Now
Hello. Add your message here.