'Killing a thread or an asynchronous task
let's say I use a jar that IBM has created. Let's say that this Jar has a function that I need but is ultimately build as such:
while (true) {
System.out.println(1)
}
(of course it doesn't really just printing 1, but for the example let's say it is) So, I made the call to the function that does it in another thread using future. How can I completely kill the thread that this code is running in? Or alternatively, how can I kill the asynchronous task in Kotlin that runs the code.
Solutions in Kotlin or Java will be great, thanks in advance!
EDIT:
I've found out, that if this is a thread, I can Thread#stop()
it to really make it stop. But unfortunately making the constructor throwing exceptions multiple times, causes the JVM to erase the class from memory causing a NoClassDefFoundError
when instantiating the class the next time..
Solution 1:[1]
If you can capture it's thread you should be able to kill it so long as it is doing some kind of blocking function internally.
class OtherFunction implements Runnable {
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// We assume the thread will exit when interrupted.
System.out.println("Bye!!");
return;
}
System.out.println("Hello");
}
}
}
class Killable implements Runnable {
final Runnable target;
private Thread itsThread;
Killable(Runnable target) {
this.target = target;
}
@Override
public void run() {
// Catch the thread id of the target.
itsThread = Thread.currentThread();
// Launch it.
target.run();
}
public void kill() {
// Give it a good kick.
itsThread.interrupt();
}
}
public void test() throws InterruptedException {
OtherFunction theFunction = new OtherFunction();
Killable killableVersion = new Killable(theFunction);
new Thread(killableVersion).start();
// Wait for a few seconds.
Thread.sleep(10000);
// Kill it.
killableVersion.kill();
}
Solution 2:[2]
It seems like Thread#stop()
solved my problem. I know it's deprecated and can be prevented with catch(Throwable t)
but at least it did the trick for me.
By the way, to get the thread from the executor, I've used AtomicReference<Thread>
and set it in the callback.
Solution 3:[3]
Thread#stop()
is deprecated as 'inherently unsafe' and should be avoided if at all possible.
It's a source of instability and corruption and may fail anyway!
It actually causes a ThreadDeath
exception to be throw in the target thread.
The authors of whatever code it pops into are unlikely to have expected that outcome.
Objects may be in an inconsistent state, external resources may be held and get leaked, files may be incompletely written.
There are ways of handling unexpected errors but in practice most code is written assuming it knows which exceptions might be thrown and not in anticipation for such a 'surprise'.
Given ThreadDeath
is a Throwable
any catch(Throwable t)
will catch it and again, unless great care was taken in every piece of code the thread might execute (unrealistic) ThreadDeath
might just get absorbed and not end the thread.
The correct way to handle this is declare an atomic variable (usually as part of the Runnable
that represents the task.
AtomicBoolean stopThread=new AtomicBoolean(false);
Then write the loop as:
while (!stopThread.get()) {
System.out.println(1);
}
And provide a method:
public void stopThread(){
stopThread.set(true);
}
Alternatively you can use interrupt()
and check interrupted()
. These are cleaner methods provided in the Thread
class. interrupted()
has the behaviour of clearing the flag when called. That's not always helpful and while the flag can be examined by Thread.currentThread().isInterrupted()
the 'checking the flag clears it' behaviour can be unhelpful and also suffers some of the issues of stop()
because it can cause "surprising" exceptions to be throw at points other code has never anticipated. The right approach is to use your own flag and be in full control of where the process decides to quit.
Take your pick.
See also: Java Thread Primitive Deprecation
Ever wondered why when you click 'Cancel' on some concurrent process you are often made to wait ages for it to respond? This is why. The task needs to come to a well defined point and do any necessary clean up to terminate in a well defined way.
Think of Thread#stop()
as like stopping a cyclist by kicking them off their bike. The method here waves a red flag at them and they then come to a halt as swiftly as they safely can.
Thread#stop()
should never have been in Java and you should never use it.
You get away with it in development and small systems. It causes havoc in large production environments.
It's not just deprecated as 'not recommended' it is 'inherently unsafe' do not use it.
It's been deprecated for years and its disappointing that some 'removal date' has never been advertised.
Here's an example that uses either Thread#stop()
or interrupt()
depending on whether you opt for being dangerous.
import java.lang.System;
import java.lang.Thread;
class Ideone
{
private static boolean beDangerous=true;//Indicates if we're going to use the Thread#stop()....
//This main method uses either stop() or interrupt() depending on the option.
public static void main (String[] args) throws java.lang.Exception
{
PrimeFactor factor=new PrimeFactor();
try{
for(int i=1;i<30;++i){
Thread thrd=new Thread(new Primer(factor));
thrd.start();
Thread.sleep(10);//Represents some concurrent processing...
if(beDangerous){
thrd.stop();
}else{
thrd.interrupt();
}
thrd.join();
if(!factor.check()){
System.out.println("Oops at "+i);
}
}
}catch(Throwable t){
System.out.println(t);
}
}
//This class just hammers the PrimeFactor object until interrupt()ed (or stop()ed).
private static class Primer implements Runnable {
private PrimeFactor factor;
public Primer(PrimeFactor ifactor){
factor=ifactor;
}
public void run(){
int i=1;
while(!Thread.interrupted()){
factor.set(i++);
}
}
}
//Don't worry about this bit too much.
//It's a class that does a non-trivial calculation and that's all we need to know.
//"You're not expected to understand this". If you don't get the joke, Google it.
//This class calculates the largest prime factor of some given number.
//Here it represents a class that ensures internal consistency using synchronized.
//But if we use Thread#stop() this apprently thread-safe class will be broken.
private static class PrimeFactor {
private long num;
private long prime;
public static long getFactor(long num){
if(num<=1){
return num;
}
long temp=num;
long factor=2;
for(int i=2;temp!=1;++i){
if(temp%i==0){
factor=i;
do{
temp=temp/i;
}while(temp%i==0);
}
}
return factor;
}
public synchronized void set(long value){
num=value;
prime=getFactor(value);
}
public synchronized boolean check(){
return prime==getFactor(num);
}
}
}
Typical partial output:
Oops at 1
Oops at 2
Oops at 3
Oops at 6
Oops at 8
Notice that the PrimeFactor
class can be described as thread-safe. All it's methods are synchronized
. Imagine it's in some library. It's unrealistic to expect "thread-safe" to mean Thread#stop()
-safe and the only way to do that would be intrusive. Putting calls to it in a try-catch(ThreadDeath tde)
block won't fix anything. The damage will have been down before it's caught.
Don't convince yourself that changing set()
to the following solves it:
public synchronized void set(long value){
long temp=getFactor(value);
num=value;
prime=temp;
}
First and foremost the the ThreadDeath
exception could throw during the assignments so all that does is potentially shorten the odds on the Race Condition. It hasn't been negated. Never make "how likely is that to happen" arguments about race conditions. Programs call methods billions of times so billion to one-shots come up regularly.
To use Thread#stop()
you can essentially never use any library objects including java.*
and jump through hoops to handle ThreadDeath
everywhere in your code and almost certainly eventually fail anyway.
Solution 4:[4]
In java there is no official way of killing thread. This is bug. (no need to argue with it here) Thread#stop() should not be deprecated. It may be improved that it cannot be consumed. Even now it will work most of the time just fine.
Right now, if I write function which will be executed with kill need, I would start new thread and joint to it with timeout or other disconnect mechanism. This will make your code to continue like main thread was killed. Problem is that main thread is still running. All resources are still in use. This is still better than application being frozen. Calling thread.interrupt() is first step but it this does not work using thread.stop() is adequate here. It won't make things worse.
If you really must kill the thread, only way would be to start another jvm via jni, run unsafe code there and use linux kill -9 to stop the whole process if needed.
I believe killing thread is perfectly possible, only jvm developers didn't care enough. I get into this situation all the time and answers like don't use any libraries, fix all foreign code, write your own language or live with it are just frustrating.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | OldCurmudgeon |
Solution 2 | Antil Karev |
Solution 3 | |
Solution 4 | Pavel Niedoba |