Home >> Java
Example using synchronized block and using wait and notify
methods on the synchronized object, in order to have a
very predictable sequence of operation performed on a
chared object instance in two separate runnable instance
in two separate thread objects.
In this example there are two runnable class files, Getter
and Setter.
Getter and Setter are designed to run within two separate
Threads and Setter is expected to retrieve the value from
the shared object "TableDrawer".
|
|  |
|
TableDrawer while returning the internally stored value
removes the value from the internal data holder.
It means TableDrawer uses the given value/counter to it,
as the key and value in a HashMap object.
For me interesting code is to use wait and notify methods
on the synchronized object inside the synchronized block
within the run methods both Setter and Getter object
instances.
Idea is to make the Setter thread wait after setting the
value into the commond shared object TableDrawer, and
then the Getter thread retrieves the value and notify
other waiting thread to start processing, so thie way
we can have a sequential setter and getter operations
one after another in a very expected way.
as shown in the image below:

In order to see the consequences by removing/commenting
wait and notify method calls in setter and getter run
methods, we an see these setter and getter operations
getting executes at an uneven way as shown below:

Now can we see and walkthrough the source code for this
example.
Setter.java
package example;
public class Setter implements Runnable {
private TableDrawer tableDrawer;
public Setter(TableDrawer td) {
tableDrawer = td;
}
public void run() {
int i=0;
while(i<1000) {
synchronized(tableDrawer) {
tableDrawer.setValue(i);
System.out.println("Setter set value: >>>> "+i);
try
{
//Makes this Thread to wait and release the lock associated
//with this shared TableDrawer object within the synchronized
//block
tableDrawer.wait();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
i++;
}
}
}
|
|
Getter.java
package example;
public class Getter implements Runnable {
private TableDrawer tableDrawer;
public Getter(TableDrawer td) {
tableDrawer = td;
}
public void run() {
int i=0;
while(i<1000) {
synchronized(tableDrawer) {
Object value = tableDrawer.getValue(i);
if(value == null)
i--;
else {
System.out.println("Getter got value:---- "+value);
//Notifies all the Thread to wakeup and move to
//runnable state by invoking notify method of the
//shared synchronized instance of the TableDrawer.
tableDrawer.notify();
}
}
i++;
}
}
}
|
|
TableDrawer.java
package example;
import java.util.Map;
import java.util.HashMap;
public class TableDrawer {
private Map store = new HashMap();
public void setValue(int v) {
store.put(new Integer(v),new Integer(v));
}
public Object getValue(int v) {
return store.remove(new Integer(v));
}
}
|
|
TestClient.java
package example;
public class TestClient {
public static void main(String args[]) {
TableDrawer td = new TableDrawer();
Thread t1 = new Thread(new Setter(td));
Thread t2 = new Thread(new Getter(td));
t1.start();
t2.start();
}
}
|
|
This TestClient instantiates two threads and attaches
Setter and Getter runnable code within these Threads
and of course passes the same insatnce of the TableDrawer
class.
After executing these example code I could understand that
wait and notify, notifyAll methods can only be executed for
an instance within the synchronized instance of that object.
Any more example code on this very aspect would be highly
appreciated.
If anything missed out , please let me know at
techienjoy at yahoo . com