当一些循环执行长任务时如何中断线程?

时间:2009-07-30 05:11:28

标签: java multithreading

可能重复: How do you kill a thread in Java?


我需要通过向线程发送中断信号来停止执行一些大任务。我正在使用java.util.concurrent。*中的大多数API。我的任务是发送到线程并执行。此任务来自客户端,因此我无法控制该代码。

任务类似于:

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);
            }

        }
    }
};

我希望在接收到中断信号时基本上停止循环for-loop(请注意我不能将Thread.interrputed()逻辑放在for循环中,因为它来自客户端。)我有另一个类使用Executor执行此任务。

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());
}

}

任务2是:

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

Task2是互为的,但Task1永远不会被中断并继续在for循环中执行。我不能在客户端代码中添加任何逻辑(类似于for循环)。我需要SO社区的帮助来解决这个问题。感谢。

9 个答案:

答案 0 :(得分:3)

唯一防弹解决方案是在隔离区中运行客户端提供的代码。隔离本质上是Java应用程序可以创建,管理和通信的私有虚拟机。特别是,父应用程序可以安全地杀死隔离及其所有线程。

参考:JSR-000121 Application Isolation API Specification - Final Release

问题是找到支持隔离的JVM。

答案 1 :(得分:2)

重新阅读您的问题并意识到您无法控制任务代码。

task1没有中断的原因是interrupt()方法实际上并没有中断任何东西,只会在线程等待某个锁或休眠时导致线程中断,否则它实际上不会除了设置状态之外的任何事情。

为您杀死task1的唯一方法是使用Thread.stop()方法。 但请注意,它可能非常危险,并使您的系统不稳定。 查看更多here

答案 2 :(得分:2)

您可以使用“停止”标志和包装类来终止您自己的任务以及客户端为您提供的任务。

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();
   }
} 

您的任务可以将控制器(“this”指针)作为构造参数,并检查其run()中的终止标志。这允许您通过调用TaskController.AbortAllTasks()来异步杀死所有这些。对于您无法控制的任务,您可以将自己的中断逻辑放在TaskController.run()中。

答案 3 :(得分:1)

中断实际上是一种合作取消机制,而不是先发制人。它需要从任务的合作做出优雅的取消。如果任务是不可中断的(即不通过检查中断状态或响应InterruptedException而中止其操作),则无法取消任务。提供中断是微不足道的;这真的是任务如何响应它。

一种可能的解决方案可能是通过动态检测等方法将代码注入任务。但是,即使这不是一个肯定的赌注,如果任务使用while循环,则需要在while循环中注入代码。

答案 4 :(得分:1)

我会提供一种机制,允许客户端代码协同处理停止信号。如果客户端代码处理信号,那么您的应用和客户同意它可以及时停止。否则,当代码返回到interrupted()检查时,您将中断该线程。我的观点是你应该要求客户代码合作而不是盲目地打断它。

答案 5 :(得分:0)

在while循环内和for循环中检查两次中断。

            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);
                    }

            }

答案 6 :(得分:0)

如果其他人在工作线程中提供代码(作为jar?),他们会根据工作的一部分调用您的代码吗?您可以将检查中断的函数放入他们调用的函数中,然后抛出一个未经检查的异常,我们希望它将终止该线程。

// 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 ...
}

小心警告编写该代码的开发人员:请参阅this article describing some of the problems that can arise

因此,简而言之,如果您不编写该代码,最好尝试让任何人检查Thread.interrupted(),以便他们可以干净地退出。

答案 7 :(得分:0)

一种停止线程的简单方法是为每个线程定义一些停止标志,然后定期检查该标志。

例如:

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
        }
    }
}

答案 8 :(得分:0)

如果不在for语句本身中进行更改,则无法进行此操作。由于Sun贬低了立即线程暂停的方法。他们有他们的理由。 (see here)唯一的方法是在循环中使用布尔值,或者,如果线程在for循环内等待,则可以捕获由Thread.interuppt()抛出的InterruptedException