2010-09-23 166 views
6

我在写一个产生多个并发任务的应用程序。我正在使用线程池来实现它。如何停止线程池中的线程

可能发生的事件发生使得任务中的计算无效。在这种情况下,我想停止当前正在运行的任务,并开始新的任务。

我的问题:如何停止当前正在运行的任务?我实现的解决方案是存储对任务线程的引用,并在此线程上调用interrupt()。在演示代码:

public class Task implements Runnable { 

    private String name; 
    private Thread runThread; 

    public Task(String name) { 
     super(); 
     this.name = name; 
    } 

    @Override 
    public void run() { 
     runThread = Thread.currentThread(); 

     System.out.println("Starting thread " + name); 
     while (true) { 
      try { 
       Thread.sleep(4000); 
       System.out.println("Hello from thread " + name); 
      } catch (InterruptedException e) { 
       // We've been interrupted: no more messages. 
       return; 
      } 
     } 
    } 

    public void stop() { 
     runThread.interrupt(); 
    } 

    public String getName() { 
     return name; 
    } 
} 

和主要方法是:

public static void main(String args[]) { 
    executorService = Executors.newFixedThreadPool(2); 

    Task t1 = new Task("Task1"); 
    Task t2 = new Task("Task2"); 
    executorService.execute(t1); 
    executorService.execute(t2); 
    executorService.execute(new Task("Task3")); 
    executorService.execute(new Task("Task4")); 

    try { 
     Thread.sleep(12000); 
     t1.stop(); 
     System.err.println("Stopped thread " + t1.getName()); 
     Thread.sleep(8000); 
     t2.stop(); 
     System.err.println("Stopped thread " + t2.getName()); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

这是一个很好的解决方案,或者有更好的办法阻止在一个线程池正在运行的线程?

+1

拔插头;) – sje397 2010-09-23 11:27:20

回答

2

在您重写的run()方法中,您将永远循环while(true)。标准行为应该是boolean runIndicator,其中run()方法在启动时设置为true,然后您的循环应为while(runIndicator)。您的stop()方法应该简单设置runIndicator = false,因此循环的下一次迭代将会失败。

+0

在这个实现中,'stop()'方法也应该调用'this.interrupt()'。在实际的实现中,应该有一个类似的方法,您可以使用它来停止正在进行的繁重工作,而不是“Thread.sleep *(4000)'调用。你可以使用一个非常类似于'runIndicator'的方法来实现这一点。 – 2010-09-23 11:34:20

+0

@Erick,'interrupt()'不是可运行的方法,所以这是不可能的。 Thread.currentThread().interrupt()'不会工作,因为stop()的调用发生在另一个线程而不是你想要中断的线程中。 – Thirler 2010-09-23 11:39:37

+1

对不起,我没有看到这个。我总是扩展'Thread'而不是'Runnable',所以我总是可以访问这些东西。我会在这里做同样的事情。这也可以解决您在答案中发布的微小线程安全问题。 – 2010-09-23 11:41:32

3

您的方法背后的想法是几个正确的解决方案之一。 Dealing with InterruptedException对如何使用中断机制给出了一个很好的概述。当你长时间计算时,这个机制主要是有用的。还有一点需要注意的是,其他库可能会通过不按照指南的说明来破坏您的中断机制(不会在未处理它时重置中断状态等)。

请注意,您的Task类不是线程安全的。您可以在保存currentThread之前停止该任务,这会产生NullPointerException。

一个更简单的方法是设置和的volatile boolean可变running代替while(true)循环做while(running)方法(这是但更普遍)。

另一个需要考虑的问题是FutureTask机制,因为它已经有一个使用中断机制的取消机制。

1

应该使用executorService.shutdown()和executorService.shutdownNow()来关闭线程池以正常退出应用程序。见ExecutorService

请参阅Qwerky关于结束当前正在运行的线程的回答。

+4

他想关闭一个线程,而不是整个池。 – 2010-09-23 11:40:32

+0

答案由Qwerky给出。但是还需要关闭线程池才能正常退出应用程序。 – 2010-09-23 12:02:22

2

您可以拿着一个参考未来

  Future<?> future = exec.submit(new Runnable() { 
     while (true){ 
     try{ 
      obj.wait(); 
     }catch(InterruptedException e){ 
      System.out.println("interrupted"); 
      return; 
     } 
     }); 
     future.cancel(true); 

布尔停止它是 - 如果运行可能会中断。

我测试了出来,并从该线程得到一个中断的异常。

如果你有cachedThreadPool,你可能需要仔细检查你是否捕获到可运行的异常,然后不要设置中断标志,因为你的线程将运行另一个未来,如果你设置中断,另一个队列未来可能无法运行。