Java 11 Removes stop() and destroy() Methods
In September 2018 Oracle finally released Java 11, following its 6 month release cycle. But why were those methods deprecated in the first place?
And how should we correctly stop threads?
As part of Java 11, Oracle finally removes the long time deprecated stop()
and destroy()
methods from the java.lang.Thread
class.
The stop()
method was considered unsafe. If a thread was stopped externally, all the monitors that the thread held became unlocked instantaneously.
That could leave shared resources and variables in an unsafe, unstable meta-state.
Consider the following class:
public class SharedClass { private int a = 1; private int b = 2; public synchronized void swap() { int temp = this.a; this.a = this.b; this.b = temp; } public synchronized void increment() { this.a++; this.b++; } }
If an object of that class is shared by multiple threads, the swap()
and the increment()
operations should be atomic. In other words, all or nothing. No intermediate state should ever been exposed.
If a thread executing the swap()
method is stopped by the stop()
method after executing a = b;
but before this.b = temp;
, the state of the shared variables a
and b
in the sharedObject are left in a corrupted and incorrect state.
Moreover, other threads can continue operating on those variables and calling the synchronized methods. And assume they are operating on correct values.
The destroy()
method had the opposite problem. The method has never actually been implemented but the idea was to stop the thread without having any cleanup. In other words, if the thread was holding any monitors, they would stay locked forever, after a thread has been destroyed.
Back to the code example. If a thread executing the swap()
method was destroyed, the remaining threads would not be able to call any methods of the shared object of type SharedClass, a situation that can also be described as a deadlock.
The methods stayed part of the JDK, but were marked as @Deprecated
for multiple version of Java.
Now at last, they are removed.
So how do you correctly stop a thread from executing?
The only correct way to stop a thread is to signal it. There are two ways to signal a thread to stop:
Using the
Thread.interrupt()
method
public class ThreadRunnable implements Runnable { @Override public void run() { while(!Thread.currentThread().isInterrupted()) { //continue executing } //cleanup and exit } }
2. Changing the state of a shared volatile
variable
public class ThreadRunnable implements Runnable { private volatile boolean isRunning = true; @Override public void run() { while(isRunning) { //continue executing } //cleanup and exit } public void stopThread() { this.isRunning = false; } }
The caveat with both ways is that the thread that you are trying to stop has to proactively check its state, and decide whether it has been externally interrupted or not.
If the thread in question detects that it has indeed been interrupted, it has to take the proper action of clean up, making sure all shared objects are left in a stable state and then and only then stop gracefully.
For more information about the latest Java 11 features click here.
The above 2 ways to stop a thread are just 2 examples of inter-thread communication. There are many other ways to coordinate between threads, not only to stop a thread but also to achieve other functionality.
A few examples include but are not limited to
Making a thread wait until a certain condition is met, and only resume shortly thereafter.
Implementation of the producer-consumer pattern.
Backpressure to avoid OOM exceptions.
Aggregating partial results from parallel computations
and many others.
To learn more about how to effectively implement inter-thread communication, to build high-performance multithreading applications click here.