Interview: How to ensure that a thread runs after another?

There are thread T1, T2 and T3, how can we ensure that thread T2 run after T1 and thread T3 run after T2?

This question was asked in my interview. I didn't answer. Please explain in detail.


Solution 1:

This would be the simplest, dumbest approach:

final Thread t1 = new Thread(new T1()); // assume T1 is a Runnable
t1.start();
t1.join();
final Thread t2 = new Thread(new T2());
t2.start();
t2.join();
final Thread t3 = new Thread(new T3());
t3.start();
t3.join();

Solution 2:

The obvious, and simplest, way has already been posted by @Assylias - have T1 run method create/start T2 and T2 run method create/start T3.

It is, IMHO, verging on pointless, but it could be done.

Solutions using Join() do not answer the question - they ensure that the termination of the threads is ordered, not the running of them. If the interviewr does not get that, you need to find another job anyway.

In an interview, my answer would be 'For * sake why? Threads are ususally used to avoid exactly what you are asking!'.

Solution 3:

One way to do it would be something like the following. It's complex though. You might want to use the java.util.concurrent.CyclicBarrier class for this.

Each thread when it finishes sets the boolean value and notifies the next thread to continue. Even though it is an AtomicBoolean class, we need the synchronized so we can wait() and notify() on it.

It would be cleaner to pass in the lock objects or maybe have a begin() method on T2 and T3 so we can hide the locks inside of those objects.

final Object lock2 = new Object();
final Object lock3 = new Object();
boolean ready2;
boolean ready3;
...
public T1 implements Runnable {
    public void run() {
        ...
        synchronized (lock2) {
            // notify the T2 class that it should start
            ready2 = true;
            lock2.notify();
        }
    }
}
...

public T2 implements Runnable {
    public void run() {
        // the while loop takes care of errant signals
        synchronized (lock2) {
            while (!ready2) {
                lock2.wait();
            }
        }
        ...
        // notify the T3 class that it should start
        synchronized (lock3) {
            ready3 = true;
            lock3.notify();
        }
    }
}
...
public T3 implements Runnable {
    public void run() {
        // the while loop takes care of errant signals
        synchronized (lock3) {
            while (!ready3) {
                lock3.wait();
            }
        }
        ...
    }
}