Threads in Java runs independently. To synchronize between threads we could use the wait() and notify() function.

Configuration
Java Compilation:
Java Runtime:
JDK 11.0.12
JRE HotSpot 11.0.12
Threads in Java runs independently. To synchronize between threads we could use the wait() and notify() function
For example, the following 2 threads, when started, will run independently and the results could vary every time the program runs:
MyOddThread.java:
public class MyOddThread extends Thread { @Override public void run() { System.out.println("One"); System.out.println("Three"); } }
MyEvenThread.java:
public class MyEvenThread extends Thread { @Override public void run() { System.out.println("Two"); System.out.println("Four"); } }
If just starts them and let them run:
public class MainClass { public static void main(String[] args) { MyOddThread myOddThread = new MyOddThread(); MyEvenThread myEvenThread = new MyEvenThread(); myOddThread.start(); myEvenThread.start(); try { myOddThread.join(); myEvenThread.join(); } catch (InterruptedException ie) { ie.printStackTrace(); } } }
The result could vary. It could be:
One
Three
Two
Four
Or the result could be:
One
Two
Four
Three
In order to synchronize between the 2 threads, we can make use of the wait() and notify() method of the Object class
We need 2 Objects for synchronization, where each object will wait() on its own notify(). We need 2 flags to indicate whether each thread should wait or proceed
For easily being referenced by both threads, these variables are stored as fields of a class - SyncInfo.java:
public class SyncInfo { Object waitObjectOddThread = new Object(); // synchronization object for MySyncOddThread to wait on Object waitObjectEvenThread = new Object(); // synchronization object for MySyncEvenThread to wait on boolean waitingOddThread = true; // flag to indicate whether MySyncOddThread should wait boolean waitingEvenThread = true; // flag to indicate whether MySyncEvenThread should wait }
Change MyOddThread to MySyncOddThread:
public class MySyncOddThread extends Thread { SyncInfo syncInfo = null; public MySyncOddThread(SyncInfo syncInfo) { this.syncInfo = syncInfo; } @Override public void run() { System.out.println("One"); synchronized (syncInfo.waitObjectEvenThread) { syncInfo.waitingEvenThread = false; // since "One" is printed, even thread no need to wait, so set waitingEvenThread to false syncInfo.waitObjectEvenThread.notify(); // since "One" is printed, need to notify even thread } try { synchronized (syncInfo.waitObjectOddThread) { if (syncInfo.waitingOddThread) { // depending on waitingOddThread (basically whether "Two" is printed or not), odd thread has to wait or not syncInfo.waitObjectOddThread.wait(); } } } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println("Three"); synchronized (syncInfo.waitObjectEvenThread) { syncInfo.waitingEvenThread = false; // since "Three" is printed, even thread no need to wait, so set waitingEvenThread to false syncInfo.waitObjectEvenThread.notify(); // since "Three" is printed, need to notify even thread } } }
Change MyEvenThread to MySyncEvenThread:
public class MySyncEvenThread extends Thread { SyncInfo syncInfo = null; public MySyncEvenThread(SyncInfo syncInfo) { this.syncInfo = syncInfo; } @Override public void run() { try { synchronized (syncInfo.waitObjectEvenThread) { if (syncInfo.waitingEvenThread) { // depending on waitingEvenThread (basically whether "One" is printed or not), even thread has to wait or not syncInfo.waitObjectEvenThread.wait(); } } } catch (InterruptedException ie) { ie.printStackTrace(); } syncInfo.waitingEvenThread = true; System.out.println("Two"); synchronized (syncInfo.waitObjectOddThread) { syncInfo.waitingOddThread = false; // since "Two" is printed, odd thread no need to wait, so set waitingOddThread to false syncInfo.waitObjectOddThread.notify(); // since "Two" is printed, need to notify odd thread } try { synchronized (syncInfo.waitObjectEvenThread) { if (syncInfo.waitingEvenThread) { // depending on waitingEvenThread (basically whether "Three" is printed or not), even thread has to wait or not syncInfo.waitObjectEvenThread.wait(); } } } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println("Four"); } }
Now run them:
public class MainClass { public static void main(String[] args) { SyncInfo syncInfo = new SyncInfo(); MySyncOddThread mySyncOddThread = new MySyncOddThread(syncInfo); MySyncEvenThread mySyncEvenThread = new MySyncEvenThread(syncInfo); mySyncOddThread.start(); mySyncEvenThread.start(); try { mySyncOddThread.join(); mySyncEvenThread.join(); } catch (InterruptedException ie) { ie.printStackTrace(); } } }
This time the result is, and always will be:
One
Two
Three
Four