This is a follow-up answer "implementation" to a question I posted on SO. For the sake of convenience, I will repeat my intent: I want one thread (called sub-thread) to print 10 times under outer-loop with 2 iterations; then another (boss-thread) to print 100 times under outer-loop with 2 iterations provided that sub-thread goes first. It will look something like this:
Sub Thread- iter = 1
Sub Thread- iter = 2
...
Sub Thread- iter = 10
Boss Thread- iter = 1
Boss Thread- iter = 2
...
Boss Thread- iter = 100
This sub-thread and boss-thread printing sequence will continue for 2 times (outer-loop).
Here's my code:
public class InterThCom {
// flag default to false for checking if sub-thread
// gets the lock first
private boolean isTh2RunFirst = false;
public static void main(String[] args) {
InterThCom itc = new InterThCom();
Thread t1 = new Thread(itc.new Th1(), "Boss-thread-");
Thread t2 = new Thread(itc.new Th2(), "Sub-thread-");
t1.start();
t2.start();
}
private class Th1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2; i++) {
synchronized (InterThCom.class) { // lock up inner-loop
// boss-thread gets the lock first
// wait for sub-thread and let it run;
// otherwise, skip this check
if (isTh2RunFirst == false) {
// wait for sub-thread, if boss-thread gets the lock first
try {
InterThCom.class.wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
// print iteration 100 times
for (int j = 0; j < 100; j++) {
System.out.println(Thread.currentThread().getName() + " iter-" + (j + 1));
}
// done printing 100 times
// sub-thread should run already at this point
isTh2RunFirst = true;
// This print helps split boss-th and sub-th prints
System.out.println(Thread.currentThread().getName() + " outer-loop iter:" + (i + 1));
// wake up sub-thread
InterThCom.class.notify();
// wait for sub-thread
try {
InterThCom.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
private class Th2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2; i++) {
synchronized (InterThCom.class) {
// print iteration 10 times
for (int j = 0; j < 10; j++) {
System.out.println(Thread.currentThread().getName() + " iter-" + (j + 1));
}
// done printing 10 times
// sub-thread already prints j iteration
isTh2RunFirst = true;
// This print helps split boss-th and sub-th prints
System.out.println(Thread.currentThread().getName() + " outer-loop iter:" + (i + 1));
// wake up boss-thread
InterThCom.class.notify();
// wait for boss-thread
try {
InterThCom.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (InterThCom.class) {
// boss-thread is waiting at the last iteration, so wake it up
InterThCom.class.notify();
}
}
}
}
Things I would like help with:
Did I use "synchronized" block in an efficient way that aligns with conventional approach?
Are there other locking approach that will make my code less cluttered and cleaner?
- My initial thought was using a separate class called
PrintStmtto wrap all the statements inside therunand then called it in the run method then lock the invocation. That way,runonly has the invocation and the lock.
- My initial thought was using a separate class called
Also, my
waitandnotifypairs are all over, is there a better way to "organize" them in a way that looks better? E.g. one of mynotifycall is outside of the double for-loop in the sub-threadTh2class. This is an edge case but I am having trouble to integrate that inside the double-loops.I am new to multi-threading. So, I am grateful for any other addresses and corrections to my implementation of the inter-communication for two threads with some extra requirement. Or other suggestions on implementing thread-communication will be appreciated.