I’m writing a program where the Main class initializes and starts a master thread. This master thread starts n slave threads. The program should terminate using Ctrl+C. Master thread must stop slave threads and finally stop itself.
I’ve read a lot about addShutdownHook and here is my simplified implementation:
package dictator;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Master m = new Master();
m.start();
}
}
class Master extends Thread {
List<Slave> slaveMonitor = new ArrayList<Slave>();
public Master() {
for (int i = 0; i < 4; i++) {
Slave slaveThread = new Slave();
slaveMonitor.add(slaveThread);
}
Thread shutDown = new Thread() {
@Override
public void run() {
try {
System.out.format("%nShutting down threads...%n");
for (Slave s : slaveMonitor) {
s.interrupt();
s.join();
}
interrupt()
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
};
Runtime.getRuntime().addShutdownHook(shutDown);
}
@Override
public void run() {
for (Slave s : slaveMonitor) {
s.start();
}
while (true) {
System.out.println(getName() + " - Master");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println(getName() + " interrupted.");
break;
}
}
System.out.println(getName() + " exiting.");
}
}
class Slave extends Thread {
public Slave() {}
@Override
public void run() {
while (true) {
System.out.println(getName() + " - Slave");
try {
Thread.sleep(1500);
} catch (InterruptedException ex) {
System.out.println(getName() + " interrupted.");
break;
}
}
}
}
The addShutdownHook catches the signal and terminates all slaves threads, but I’m not seen the master thread exiting (lines System.out.println(getName() + " interrupted."); and System.out.println(getName() + " exiting."); in master’s run body.
Here is my terminal’s output:
Thread-1 - Slave
Thread-2 - Slave
Thread-3 - Slave
Thread-0 - Master
Thread-4 - Slave
Thread-0 - Master
^C
Shutting down threads...
Thread-1 interrupted.
Thread-2 interrupted.
Thread-3 interrupted.
Thread-4 interrupted.
Shouldn’t I see the line following lines? What I’m I doing wrong?
Thread-0 interrupted.
Thread-0 exiting.
Changed Master Thread
class Master extends Thread {
List<Slave> slaveMonitor = new ArrayList<>();
List<Thread> killList = new ArrayList<>();
public Master() {
for (int i = 0; i < 4; i++) {
Slave slaveThread = new Slave();
slaveMonitor.add(slaveThread);
}
killList.add(this);
Thread shutDown = new Thread() {
@Override
public void run() {
try {
killList.addAll(slaveMonitor);
Collections.reverse(killList);
System.out.format("%nShutting down threads...%n");
for (Thread t : killList) {
t.interrupt();
t.join();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
System.out.println("Interrupted shutdown process");
System.exit(1);
}
}
};
Runtime.getRuntime().addShutdownHook(shutDown);
}
...
Your shutdown thread never interrupt the master thread. It is a separate thread from the Master thread so when you call
in its body you are asking this thread to interrupt itself. You need to add the master thread to the list of thread to terminate.
Change your code to :
and use the
killListto terminate threads.