4

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

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

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

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

提前致谢。

4

3 回答 3

7

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

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

如果实施正确,这里有几种方法应该可行。

  1. 您可以让两个线程定期检查一些公共标志变量(例如调用它stopNow),并安排两个线程在完成时设置它。(标志变量需要是易变的......或正确同步。)

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


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

据我所知,Corsika 的代码假定有一种stop()方法可以在调用时执行正确的操作。真正的问题是你是如何实现它的?或者您打算如何实施?

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

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

感谢您的建议,但我有疑问,“定期检查/呼叫”如何转化为代码?

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

于 2012-12-01T05:30:54.360 回答
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();
                    }
                }
            }
        }
    }

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

于 2012-12-01T13:27:29.233 回答
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);
}
于 2012-12-01T04:08:55.700 回答