Today in next part of the series we will talk about How to communicate among threads using Lock and Condition Objects.
In traditional Java-If we need to communicate among threads, we syncronize code and use "wait" and "policy" methods of Object class.
From Java 5.0 and above-Lock interface provides an easier implmentation for synchronization and Condition class can be used to wait and has y threads.
Lock has several important methods such as "lock", "tryLock", "lockInterruptibly" etc, whereas Condition has "await", "signal", 'signalall "etc. in this article we will demonstrate the usage of 3 methods-"lock" (from Lock interface), "await", "signal" (from Condition Class ).
Lets try to visualize a scenario here-Assume we have 2 process "Reader" and "Writer ". writer writes on a file and Reader reads from a file. we want to add a listener to writer object so that whenever writer writes anything on a file, "Reader" will be called and it will read the same data. before we look into codes lets look at the some important points to use Lock and Condition-
1) Lock is an Interface, the most common implementation class is ReentrantLock. Others two are-ReentrantReadWriteLock. ReadLock, ReentrantReadWriteLock. WriteLock
2) Condition Object is always retrieved from Lock object. For example-Condition condition = lock. newCondition ();
3) One of the best practice to use Lock is-
Lock lockObj = new ReentrantLock ();
LockObj. lock ();
Try {
... Code ..
} Finally {
LockObj. unlock ();
}
4) condition. await, condition. signal, condition. signalAll methods shocould only be called once you have acquired the lock by-lockObj. lock ().
In our example, the design of the class will be something like this-
> One lock Object = fileLock
> One condition Object = condition = fileLock. newCondition
Pseudo code for Writer Thread
// GET the LOCK
Try {
// -- In the Loop untill EXIT ---
// Write on the file
// Signal the READER
// If EXIT signal then exit else "WAIT for READER to SIGNAL"
} Finally {
// RELEASE the LOCK
}
Pseudo code for Reader Thread
// GET the LOCK
Try {
// -- In the Loop untill EXIT ---
// Read from the file
// Signal the WRITER
// If EXIT signal-then exit else "WAIT for WRITER to SIGNAL"
} Finally {
// RELEASE the LOCK
}
Package com. jovialjava. blog. threads;
Import java. io. BufferedReader;
Import java. io. File;
Import java. io. FileReader;
Import java. io. PrintWriter;
Import java. security. SecureRandom;
Import java. util. concurrent. ExecutorService;
Import java. util. concurrent. Executors;
Import java. util. concurrent. locks. Condition;
Import java. util. concurrent. locks. Lock;
Import java. util. concurrent. locks. ReentrantLock;
Public class LockExample {
Private static final String fileName = "LockExample.txt ";
Private static final String EXIT_FLAG = "BYE ";
Private static final int NO_OF_LINES = 10;
Private static final Lock fileLock = new ReentrantLock ();
Private static final Condition condition = fileLock. newCondition ();
Private static final ExecutorService executorPool = Executors. newFixedThreadPool (2 );
Public static void main (String args ){
Runnable fileWriter = new FileWrite ();
Runnable fileReader = new FileRead ();
ExecutorPool. submit (fileReader );
ExecutorPool. submit (fileWriter );
ExecutorPool. shutdown ();
}
/**
* This thread will write on a file and inform the reader thread to read it.
* If it has not written the EXIT flag then it will go into wait stage and
* Will wait for READER to signal that it safe to write now.
*/
Public static class FileWrite implements Runnable {
Public void run (){
Try {
FileLock. lock ();
For (int I = 0; I <NO_OF_LINES; I ++ ){
PrintWriter writer = new PrintWriter (new File (fileName ));
If (I! = NO_OF_LINES-1 ){
Int random = new SecureRandom (). nextInt ();
System. out. println ("writer writing" + random );
Writer. println (random );
Writer. close ();
// Signallng to READER that its safe to read now.
Condition. signal ();
System. out. println ("Writer waiting ");
Condition. await ();
} Else {
Writer. println (EXIT_FLAG );
System. out. println ("writer exiting ");
Writer. close ();
// AS it was an exit flag so no need to wait, just
// Signal the reader.
Condition. signal ();
}
}
} Catch (Exception e ){
System. out. println ("!!!!!!!!!!!!!!!!!!!!!!!! EXCEPTION !!!!!!!!!!!!!!!!!!!!!!!! ");
E. printStackTrace ();
} Finally {
FileLock. unlock ();
// Delete the file, require in case if one wants to run demo
// Again.
File file = new File (fileName );
File. delete ();
Try {
File. createNewFile ();
} Catch (Exception e ){
}
}
}
}
/**
* This thread will read from the file and inform the writer thread to write
* Again. If it has not read the EXIT flag then it will go into wait stage
* And will wait for WRITER to signal that it safe to read now.
*/
Public static class FileRead implements Runnable {
Public void run (){
String data = null;
FileLock. lock ();
Try {
While (true ){
BufferedReader reader = new BufferedReader (new FileReader (fileName ));
Data = reader. readLine ();
System. out. println ("read data-" + data );
Reader. close ();
If (data = null |! Data. equals (EXIT_FLAG )){
Condition. signalAll ();
System. out. println ("Reader Waiting ");
Condition. await ();
} Else {
System. out. println ("reader exiting ");
Condition. signal ();
Break;
} Www.2cto.com
}
} Catch (Exception e ){
System. out. println ("!!!!!!!!!!!!!!!!!!!!!!!! EXCEPTION !!!!!!!!!!!!!!!!!!!!!!!! ");
E. printStackTrace ();
} Finally {
FileLock. unlock ();
}
}
}
}
Author: silence is gold