Introduction
Recently, I was involved in a project, in which several threads need to be stopped. However, the stop()
in Thread
class is deprecated. Here is an article published by Oracle stating why they think this method (and some related others) should not be used.
Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?
This article also provides safe alternative for those deprecated. Here I list some test code based on my understanding. Three cases are tested, as below.
- stopFlag method
interrupt()
method- Multiple threads
Cases
stopFlag method
A volatile field called stopFlag is set to be false
initially. The run()
method of the Thread
object keeps monitor this field. The stop()
method will set stopFlag to be true
. Then run()
method will be stopped.
private static class ThreadTestSignal {
private Thread thread;
private volatile boolean stopFlag = false;
public ThreadTestSignal() {
thread = new Thread() {
@Override
public void run() {
while (!stopFlag) {
System.out.println("working");
}
}
};
}
public void start() {
thread.start();
}
public void stop() {
this.stopFlag = true;
}
}
interrupt()
method
The run()
method of Thread
object keeps monitor the value of currentThread.isInterrupted()
or Thread.interrupted()
. The stop()
method will run currentThread.interrupt()
. It has an advantage comparing with the stopFlag method. While the thread has a long sleep or wait, InterruptedException
will be catched during sleep once interrupted, thus run()
method will return and the thread will be stopped. But stopFlag method may need some time (due to sleep) to reach the stopFlag monitoring line.
private static class ThreadTestInterrupt {
private Thread thread;
public ThreadTestInterrupt() {
thread = new Thread() {
@Override
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
System.out.println("Interrupted");
return;
}
System.out.println("working");
}
}
};
}
public void start() {
thread.start();
}
public void stop() {
thread.interrupt();
}
}
Multiple threads
Actually, we don’t really need a boolean
stopFlag. For the multiple threads case, a map (a set will be enough though) can be used. We put the thread ID for each thread in this map. It’s equivalent to maintain a boolean
stopFlag for each thread. In stop()
method, the map will be cleared, just like setting all stopFlags to be true
.
private static class ThreadTestMultiSignal {
private volatile ConcurrentMap<Integer, Integer> threadsMap;
private static final int numThreads = 10;
public ThreadTestMultiSignal() {
threadsMap = new ConcurrentHashMap<>();
for (int i = 0; i < numThreads; i++) {
threadsMap.put(i, 0);
}
for (Integer noThread : threadsMap.keySet()) {
new Thread() {
@Override
public void run() {
while (threadsMap.containsKey(noThread)) {
System.out.println("working thread: " + noThread);
}
}
}.start();
}
}
public void stop() {
threadsMap.clear();
}
}
Main test code
The main function for test is as below.
public static void main(String[] args) {
// For signal method
System.out.println("Signal method, start");
ThreadTestSignal testSignal = new ThreadTestSignal();
testSignal.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
testSignal.stop();
System.out.println("Signal detected, stopped");
// For interrupt method
System.out.println("Interrupt method, start");
ThreadTestInterrupt testInterrupt = new ThreadTestInterrupt();
testInterrupt.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
testInterrupt.stop();
System.out.println("Thread interrupted, stopped");
//For Multiple threads
System.out.println("Multiple threads, start");
ThreadTestMultiSignal testMultiSignal = new ThreadTestMultiSignal();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
testMultiSignal.stop();
System.out.println("Multiple signals detected, stopped");
}