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
PrintStmt
to wrap all the statements inside therun
and then called it in the run method then lock the invocation. That way,run
only has the invocation and the lock.
- My initial thought was using a separate class called
Also, my
wait
andnotify
pairs are all over, is there a better way to "organize" them in a way that looks better? E.g. one of mynotify
call is outside of the double for-loop in the sub-threadTh2
class. 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.