给定两个Java线程,当其中一个线程完成时停止一个线程

我正在为这个问题寻找一个干净的设计/解决方案:我有两个线程,可以在用户想要的时候运行,但最终在用户发出stop命令时停止。 但是,如果其中一个线程突然结束(例如,由于运行时exception),我想停止另一个线程。

现在两个线程都执行一个Runnable (所以当我说’停止一个线程’我的意思是我在Runnable实例上调用一个stop()方法),我在想的是避免使用线程(Thread类)并使用CompletionService接口然后将两个Runnables提交给此服务的实例。

有了这个,我会使用CompletionService的方法take() ,当这个方法返回时,我会停止两个Runnables,因为我知道它们中至少有一个已经完成了。 现在,这有效,但如果可能的话,我想知道一个更简单/更好的解决方案。

另外,当我们有n线程并且只要其中一个线程完成停止执行所有其他线程时,什么是一个好的解决方案?

提前致谢。

没有Runnable.stop()方法,所以这是一个明显的非首发。

不要使用Thread.stop() ! 在绝大多数情况下,它基本上是不安全的。

如果正确实施,以下是一些应该有效的方法。

  1. 您可以让两个线程定期检查一些常见的标志变量(例如将其stopNow ),并安排两个线程在完成时设置它。 (标志变量需要是易失性的……或者是正确同步的。)

  2. 您可以让两个线程定期调用Thread.isInterrupted()方法来查看它是否已被中断。 然后每个线程在完成时需要在另一个线程上调用Thread.interrupt()


我知道Runnable没有那个方法,但是我传递给线程的Runnable的实现确实有它,并且当调用它时,运行器将完成run()方法(类似于Corsika的代码,在这个答案之下)。

从我所知道的,Corsika的代码假定有一个stop()方法在调用时会做正确的事情。 真正的问题是你是如何实现它的? 或者你打算如何实现它?

  • 如果您已经有一个可行的实现,那么您就可以找到问题的解决方案。

  • 否则,我的回答提供了两种可能的方法来实现“立即停止”function。

我感谢您的建议,但我有一个疑问,“定期检查/致电”如何翻译成代码?

它完全取决于Runnable.run()方法执行的任务。 它通常需要在某些循环中添加检查/调用,以便经常合理地进行测试……但不要太频繁。 您还想检查何时可以安全地停止计算,这是您必须自己解决的另一件事。

以下内容应该有助于您了解如何将其应用于您的问题。 希望能帮助到你…

  import java.util.*; public class x { public static void main(String[] args) { ThreadManager t = new ThreadManager(); Thread a = new MyThread(t); Thread b = new MyThread(t); Thread c = new MyThread(t); t.add(a); t.add(b); t.add(c); a.start(); b.start(); c.start(); } } class ThreadManager extends ArrayList { public void stopThreads() { for (T t : this) { Thread thread = (Thread) t; if (thread.isAlive()) { try { thread.interrupt(); } catch (Exception e) {/*ignore on purpose*/} } } } } class MyThread extends Thread { static boolean signalled = false; private ThreadManager m; public MyThread(ThreadManager tm) { m = tm; } public void run() { try { // periodically check ... if (this.interrupted()) throw new InterruptedException(); // do stuff } catch (Exception e) { synchronized(getClass()) { if (!signalled) { signalled = true; m.stopThreads(); } } } } } 

无论您使用停止标志还是中断,您都需要定期检查线程是否已发出停止信号。

您可以让他们互相访问,或者回调某些可以访问这两者的东西,这样就可以打断另一个。 考虑:

 MyRunner aRunner = new MyRunner(this); MyRunner bRunner = new MyRunner(this); Thread a = new Thread(aRunner); Thread b = new Thread(brunner); // catch appropriate exceptions, error handling... probably should verify // 'winner' actually is a or b public void stopOtherThread(MyRunner winner) { if(winner == aRunner ) bRunner .stop(); // assumes you have stop on class MyRunner else aRunner.stop(); } // later a.start(); b.start(); // in your run method public void run() { // la de da de da // awesome code while(true) fork(); // other code here myRunnerMaster.stopOtherThread(this); }