If the execution of code depends on the state of an object in order to read or modify its attributes or invoke its methods,
then it is possible to put the thread executing this code on hold, waiting for another thread that manipulates the object to send a notification indicating that the object is now ready to be used.
For example, if an application uses two threads, where:
- one is responsible for constructing the elements of an array,
- and the other is responsible for sorting the array elements once all elements have been provided.
Then, both threads can use the
wait
and
notify
methods to synchronize access to this object.
package com.mtitek.threads;
class MyClass {
private volatile boolean ready = false;
private Integer[] elements;
public synchronized boolean isReady() {
return ready;
}
public synchronized void setReady(boolean ready) {
this.ready = ready;
}
public synchronized Integer[] getElements() {
return elements;
}
public synchronized void setElements(Integer[] elements) {
this.elements = elements;
}
}
public class MainClass {
public static void main(String[] args) {
final MyClass myClass = new MyClass();
Runnable myRunnable1 = new Runnable() {
@Override
public void run() {
synchronized (myClass) {
try {
// Wait while another thread might be using the object
while (myClass.isReady()) {
myClass.wait();
}
// Code to be executed by the thread
System.out.println(
Thread.currentThread().getName() + " (" + Thread.currentThread().threadId() + ")");
System.out.println("Initializing array elements (start)");
myClass.setElements(new Integer[] { 4, 2, 8, 1, 6 });
System.out.println("Initializing array elements (end)");
// Mark as ready and notify waiting threads
myClass.setReady(true);
myClass.notify();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupted status
System.err.println(Thread.currentThread().getName() + " was interrupted: " + e.getMessage());
}
}
}
};
Runnable myRunnable2 = new Runnable() {
@Override
public void run() {
synchronized (myClass) {
try {
// Wait until data is ready
while (!myClass.isReady()) {
myClass.wait();
}
// Process the data
System.out.println(
Thread.currentThread().getName() + " (" + Thread.currentThread().threadId() + ")");
System.out.println("Sorting and displaying array elements (start)");
Integer[] elements = myClass.getElements();
if (elements != null) {
// Sort the array
java.util.Arrays.sort(elements);
for (Integer element : elements) {
System.out.println(element);
}
}
System.out.println("Sorting and displaying array elements (end)");
// Reset state and notify
myClass.setReady(false);
myClass.notify();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupted status
System.err.println(Thread.currentThread().getName() + " was interrupted: " + e.getMessage());
}
}
}
};
Thread myThread1 = new Thread(myRunnable1, "myFirstThread");
Thread myThread2 = new Thread(myRunnable2, "mySecondThread");
myThread1.start();
myThread2.start();
// Wait for threads to complete
try {
myThread1.join();
myThread2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Main thread was interrupted: " + e.getMessage());
}
}
}
Output:
myFirstThread (19)
Initializing array elements (start)
Initializing array elements (end)
mySecondThread (20)
Sorting and displaying array elements (start)
1
2
4
6
8
Sorting and displaying array elements (end)