I need to make sequence of threads. They need to start in order like this:
A then B then C and finally D.
When D is finished then C can finish then B, then A.
In this situation what is better to use join()
threads or wait()
? and why?
My threads need to start and print the message Hello I'm thread a/b/c/d
and when they are finished they need to print I'm finished a/b/c/d
.
Bearing in mind that join
and wait
do very different things and aren't really related, and also bearing in mind that the example you gave is really, really strange, either choice could potentially be the one you're looking for.
join
is probably the easier choice. The thread calling join
will wait until the other thread has finished execution. So, each thread in this case will need to hold a reference to the next thread, and it'll call join
right before printing "I'm finished". So your class might look like this:
class JoiningThread extends Thread {
// NOTE: UNTESTED!
private String name;
private Thread nextThread;
public JoiningThread(String name) {
this(name, null);
}
public JoiningThread(String name, Thread other) {
this.name = name;
this.nextThread = other;
}
public String getName() {
return name;
}
@Override
public void run() {
System.out.println("Hello I'm thread ".concat(getName()));
if (nextThread != null) {
while(nextThread.isAlive()) {
try {
nextThread.join();
} catch (InterruptedException e) {
// ignore this
}
}
}
System.out.println("I'm finished ".concat(getName()));
}
}
And the main method could be:
public static void main(String[] args) {
Thread d = WaitingThread("d");
Thread c = WaitingThread("c", d);
Thread b = WaitingThread("b", c);
Thread a = WaitingThread("a", b);
a.start();
b.start();
c.start();
d.start();
try {
a.join();
} catch (InterruptedException e) {}
}
What wait
does is suspend the execution of a thread until notify
or notifyAll
is called. So to implement this idea with wait
, you need each thread to hold a reference to the thread before it. The strategy is for the run
method to finish with a call to wait
, followed by a call to notify
the previous thread that execution has finished. So your class might look something like this:
class WaitingThread extends Thread {
// NOTE: UNTESTED!
private Thread previousThread;
private String name;
public WaitingThread(String name) {
this(name, null);
}
public WaitingThread(String name, Thread other) {
this.name = name;
this.previousThread = other;
}
public String getName() {
return name;
}
@Override
public void run() {
System.out.println("Hello I'm thread ".concat(getName()));
// Do other things if required
// Wait to be woken up
while(true) {
synchronized(this) {
try {
wait();
break;
} catch (InterruptedException e) {
// ignore this
}
}
}
System.out.println("I'm finished ".concat(getName()));
// Wake up the previous thread
if (previousThread != null) {
synchronized(previousThread) {
previousThread.notify();
}
}
}
}
And the main
method that sets everything up from the main thread might be:
public static void main(String[] args) {
Thread a = WaitingThread("a");
Thread b = WaitingThread("b", a);
Thread c = WaitingThread("c", b);
Thread d = WaitingThread("d", c);
a.start();
b.start();
c.start();
d.start();
while(true) {
// wake up d once it goes to sleep
if (d.isAlive()) {
d.notify();
}
}
}
Since you are waiting for the 'other' thread to complete (i.e. finish execution), join()
would be the better choice.
The javadoc for join()
says simply: Waits for this thread to die.
The mechanism is then relatively simple:
@Override
public void run() {
System.out.println("Hello I'm thread " + getName());
if (otherThread != null) {
while (otherThread.isAlive()) {
try {
otherThread.join();
} catch (InterruptedException e) {
// ignore
}
}
}
System.out.println("I'm finished " + getName());
}
To explain: you need to have a reference to the otherThread
. So a
refers to b
, b
refers to c
, c
refers to d
and d
doesn't refer to any otherThread
(it's null).
The statement otherThread.join()
waits for the other thread to complete. It is wrapped in a loop since join()
can throw InterruptedException
(though rarely in practise).
Hope this helps, good luck.
The join()
method is used to wait for a thread to complete execution. The join()
method of a Thread instance can be used to "join" the start of a thread's execution to the end of another thread's execution so that a thread will not start running until another thread has ended. If join()
is called on a Thread instance, the currently running thread will block until the Thread instance has finished executing.
An example of join()
The wait()
method is used to wait for a notification to be sent on an object. The two conditions are pretty distinctive.
An example and more explanation of wait()
I would do it this way
public class Test1 extends Thread {
static Object lock = new Object();
static int n;
int i;
String name;
Test1(String name, int i) {
this.name = name;
this.i = i;
}
@Override
public void run() {
try {
synchronized (lock) {
while (i != n) {
lock.wait();
}
System.out.println(name + " started");
n++;
lock.notifyAll();
}
synchronized (lock) {
while (i != n - 4) {
lock.wait();
}
System.out.println(name + " finished");
n++;
lock.notifyAll();
}
} catch (InterruptedException e) {
}
}
public static void main(String[] args) throws Exception {
new Test1("a", 0).start();
new Test1("b", 1).start();
new Test1("c", 2).start();
new Test1("d", 3).start();
}
}
output
a started
b started
c started
d started
a finished
b finished
c finished
d finished
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With