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

时间:2012-12-01 04:04:01

标签: java concurrency runnable

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

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

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

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

提前致谢。

3 个答案:

答案 0 :(得分:7)

没有Runnable.stop()方法,所以这显然是非首发。

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

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

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

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


  3.   

    我知道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);
}