我正在为这个问题寻找一个干净的设计/解决方案:我有两个线程,可以在用户想要的时候运行,但最终在用户发出stop命令时停止。但是,如果其中一个线程突然结束(例如,由于运行时异常),我想停止另一个线程。
现在两个线程都执行Runnable
(所以当我说'停止线程'我的意思是我在Runnable
实例上调用stop()方法),我在想什么是避免使用线程(Thread类)并使用CompletionService
接口,然后将两个Runnables提交给此服务的实例。
有了这个,我会使用CompletionService的方法take()
,当这个方法返回时,我会停止两个Runnables,因为我知道其中至少有一个已经完成。现在,这有效,但如果可能的话,我想知道一个更简单/更好的解决方案。
另外,当我们有n
个线程时,只要其中一个线程完成停止执行所有其他线程,什么是一个好的解决方案?
提前致谢。
答案 0 :(得分:7)
没有Runnable.stop()
方法,所以这显然是非首发。
不要使用Thread.stop()
!在绝大多数案例中,它基本上是不安全的。
如果正确实施,以下是一些应该有效的方法。
您可以让两个线程定期检查一些常见的标志变量(例如,将其称为stopNow
),并安排两个线程在完成时设置它。 (标志变量需要是易失性的......或者是正确同步的。)
您可以让两个线程定期调用Thread.isInterrupted()
方法来查看它是否已被中断。然后每个线程在完成时需要在另一个线程上调用Thread.interrupt()
。
我知道Runnable没有那个方法,但是我传递给线程的Runnable的实现确实有它,并且在调用它时,运行器将完成run()方法(类似于Corsika的代码,在这个答案之下) )。
据我所知,Corsika的代码假设有一个stop()
方法在调用时会做正确的事情。真正的问题是你是如何实现它的?或者你打算如何实现它?
如果您已经有一个有效的实施方案,那么您就可以找到问题的解决方案。
否则,我的回答提供了两种实现“立即停止”功能的方法。
感谢您的建议,但我有疑问,“定期检查/致电”如何翻译成代码?
这完全取决于Runnable.run()
方法执行的任务。它通常需要在某些循环中添加检查/调用,以便经常合理地进行测试......但不要太频繁。您还想检查何时可以安全地停止计算,这是您必须自己解决的另一件事。
答案 1 :(得分:4)
以下内容应该有助于您了解如何将其应用于您的问题。希望它有所帮助...
import java.util.*;
public class x {
public static void main(String[] args) {
ThreadManager<Thread> t = new ThreadManager<Thread>();
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<T> extends ArrayList<T> {
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();
}
}
}
}
}
无论您使用停止标志还是中断,您都需要定期检查线程是否已发出停止信号。
答案 2 :(得分:1)
你可以让他们互相访问,或者回访可以访问两者的东西,这样就可以打断另一个。考虑:
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);
}