1

Possible Duplicate: How do you kill a thread in Java?


I need to stop doing some big task by sending the interruption signal to the Thread. I am using most of the APIs from java.util.concurrent.*. My task is send to the Thread and is executed. This task comes from the client so I do not have any control over that code.

Task are something similar to:

public class Task1 extends Thread {
    public void run() {
        while(true){
            if(Thread.interrupted()){
                return;
            }
            for(int i=0; i<Integer.MAX_VALUE; i++){
                System.out.println("I am task 1 " + i);
            }

        }
    }
};

I want to basically stop looping through the for-loop when it receives the interruption signal (Please note that I cannot put the Thread.interrputed() logic inside for-loop as it comes from the client.) I have another class that use the Executor to execute this task.

public class ConcurrentTest {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    ConcurrentTest test = new ConcurrentTest();
    ExecutorService executorService = Executors.newFixedThreadPool(2);

    Task1 task1 = new Task1();
    Future<?> runningTask1 = executorService.submit(task1);

    Task2 task2 = new Task2();
    Future<?> runningTask2 = executorService.submit(task2);

    //Stop First task after 5 second
    try {
        TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    runningTask1.cancel(Boolean.TRUE);
    System.out.println("runningTask1.isDone is " + runningTask1.isDone());
    System.out.println("runningTask1.isCancelled is " + runningTask1.isCancelled());
    //Stop Second task after 10 second
    try{
        TimeUnit.SECONDS.sleep(3);
    }catch(InterruptedException e){
        e.printStackTrace();
    }
    runningTask2.cancel(Boolean.TRUE);
    System.out.println("runningTask2.isDone is " + runningTask2.isDone());
    System.out.println("runningTask2.isCancelled is " + runningTask2.isCancelled());
}

}

Task2 is :

public class Task2 extends Thread{
    public void run() {
        while(true){
            if(Thread.interrupted()){
                return;
            }
            System.out.println("I am task 2");
        }
    }
};

Task2 is interrpted however Task1 is never interrupted and continue executing inside for loop. I cannot put any logic inside client code (something similar to for-loop). I need help from SO community to resolve this issue. Thanks.

Community
  • 1
  • 1
royalghost
  • 2,773
  • 5
  • 23
  • 29
  • It's not clear to me why you can't put a check of Thread.interrupted in Thread 1's for loop. – RossFabricant Jul 30 '09 at 05:15
  • Possible duplicate of [How do you kill a Thread in Java?](https://stackoverflow.com/questions/671049/how-do-you-kill-a-thread-in-java) – Cœur Jul 09 '18 at 14:19

9 Answers9

3

The only bomb-proof solution is to run the client supplied code in an Isolate. An isolate is essentially a private virtual machine that a Java app can create, managed and communicate with. In particular, the parent app can safely kill an isolate and all its threads.

Reference: JSR-000121 Application Isolation API Specification - Final Release

The problem is finding a JVM that supports Isolates.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2

Re-read your questions and realized you don't have any control over the tasks code.

The reason why task1 doesn't interrupt is that interrupt() method doesn't actually interrupt anything, it will only cause the thread to interrupt if that thread is waiting on some lock or sleeping, otherwise it doesn't actually do anything except setting the status.

The only way to kill task1 for you is to use Thread.stop() method. Be careful though is it can be very dangerous and make your system unstable. See more here.

Gregory Mostizky
  • 7,231
  • 1
  • 26
  • 29
2

You can use a "stop" flag and a wrapper class to kill both your own tasks and the ones the client gives you.

public class MyTask implements Runnable {
   private TaskController taskControl;

   @Override
   public void run() {
     if(taskControl.abort()) {
       return;
     }
     // Task logic ...
   }
}

// Construct on main thread, call "run()" on a dedicated background thread.
public class TaskController implements Runnable {
   private AtomicBoolean terminate = new AtomicBoolean(false);
   private ThreadPoolExecutor yourTaskThreadPool;
   private ThreadPoolExecutor otherTaskThreadPool;

   @Override
   public void run() {
     // Your task construction, dispatch logic. Use your own thread pool

     // Run the tasks you don't control in THEIR own pool
     if(terminate.get()) {
       otherTaskThreadPool.shutdown();
     }
     otherTaskThreadPool.execute( clientsTask ); // e.g. "task1"
   }

   public void AbortAllTasks() {
       terminate.set(true);
   }

   public boolean abort() {
       return terminate.get();
   }
} 

Your tasks can take the controller ("this" pointer) as a construction parameter, and check the terminate flag in their run(). This allows you to asynchronously kill all of them by just calling TaskController.AbortAllTasks(). For the tasks you don't control, you can put your own interrupt logic in TaskController.run().

LPL
  • 16,827
  • 6
  • 51
  • 95
Zack Yezek
  • 21
  • 1
1

Interruption is really a cooperative cancellation mechanism, not a preemptive one. It takes the cooperation from the task to do a graceful cancellation. If the task is uninterruptible (i.e. does not abort its action by checking the interrupt status or responding to the InterruptedException), there is not much you can do to cancel the task. Delivering the interrupt is trivial; it's really how the task responds to it.

One possible solution might be to inject your code into the task via things like dynamic instrumentation. However, even that is not a sure bet, and it would require injecting your code inside the while loop if the task uses a while loop.

sjlee
  • 7,726
  • 2
  • 29
  • 37
1

I would provide a mechanism that allows client code to handle the stopping signal cooperatively. If the client code handles signal, then your app and the client agree that it can do stopped in timely manner. Otherwise, you interrupt the thread when the code gets back to your interrupted() checking. My point is that you should ask the client code to be cooperative instead of interrupting it blindly.

weilin8
  • 2,975
  • 3
  • 32
  • 36
0

Check for interrupt twice inside the while loop and in the for loop.

            while(true){
                    if(Thread.interrupted()){
                            return;
                    }
                    for(int i=0; i<Integer.MAX_VALUE; i++){
                         if(Thread.interrupted()){
                              return;
                         }

                         System.out.println("I am task 1 " + i);
                    }

            }
  • "Please note that I cannot put the Thread.interrputed() logic inside for-loop as it comes from the client." – erickson Jul 30 '09 at 05:26
  • Yes, I don't have control over the task (like for-loop here) as it comes from the client. – royalghost Jul 30 '09 at 05:45
  • What you could do is create another thread which would periodically check the state of your running threads, and invoke the stop() (err... it's deprecated but still works) method on the thread to force it to terminate when so necessary. However, this is very unsafe and ugly. If your thread is using shared resource and becomes terminated you may have a deadlock in your application as nobody else would be able to access that shared resource since the thread terminated without cleanup. Unfortunately, i don't see an elegant solution to this. –  Jul 30 '09 at 06:39
  • Actually, i may have to take the deadlock issue back. According to this http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html stop() will unlock all monitors, so now you may be potentially dealing with your shared resource being released in inconsistent or damaged state. –  Jul 30 '09 at 06:45
0

If someone else is providing the code in the worker thread (as a jar?) do they call your code at all as part of their work? You could put the check for interrupted in functions you write that they call and throw an unchecked exception that we hope will terminate the thread.

// Called from the worker thread code that someone else writes,
// hopefully often so that we notice when we're interrupted.
public void doSomething() {
  if (Thread.interrupted()) {
    throw new MyRuntimeException();
  }
  // do what this method is meant to do ...
}

Be careful to warn the developers writing that code: see this article describing some of the problems that can arise.

So, in short, if you're not writing that code, it's best to try to get whoever is to check for Thread.interrupted() so that they can exit cleanly.

Harold L
  • 5,166
  • 28
  • 28
0

A simple approach to stopping threads is to define some stop flag for each thread and then periodically check that flag.

For example:

class MyTask implements Runnable {
    private AtomicBoolean stopflag = new AtomicBoolean();
    public void stop() {
        stopflag.set(true);
    }

    public void run() {
        while(true) {
            if(!stopflag.get()) 
                /// do some work
            else
                return;   // get out
        }
    }
}
Gregory Mostizky
  • 7,231
  • 1
  • 26
  • 29
0

You can NOT make it without putting changes in the for statement itself. as Sun depracated the methods for immediate Thread suspension. and they had their reasons. (see here) the only way to do that is to use a boolean inside the loop, or, if the Thread sleeps\wait inside the for loop, you can catch InterruptedException that is thrown by Thread.interuppt()

Ofek Ron
  • 8,354
  • 13
  • 55
  • 103