Given two Java threads, stop one thread when one of them finishes

会有一股神秘感。 提交于 2019-11-29 14:38:29

There is no Runnable.stop() method, so that is an obvious non-starter.

Don't use Thread.stop()! It is fundamentally unsafe in the vast majority of cases.

Here are a couple of approaches that should work, if implemented correctly.

  1. You could have both threads regularly check some common flag variable (e.g. call it stopNow), and arrange that both threads set it when they finish. (The flag variable needs to be volatile ... or properly synchronized.)

  2. You could have both threads regularly call the Thread.isInterrupted() method to see if it has been interrupted. Then each thread needs to call Thread.interrupt() on the other one when it finishes.


I know Runnable doesn't have that method, but my implementation of Runnable that I pass to the threads does have it, and when calling it the runner will finish the run() method (something like Corsika's code, below this answer).

From what I can tell, Corsika's code assumes that there is a stop() method that will do the right thing when called. The real question is how have you do implemented it? Or how do you intend to implement it?

  • If you already have an implementation that works, then you've got a solution to the problem.

  • Otherwise, my answer gives two possible approaches to implementing the "stop now" functionality.

I appreciate your suggestions, but I have a doubt, how does 'regularly check/call' translate into code ?

It entirely depends on the task that the Runnable.run() method performs. It typically entails adding a check / call to certain loops so that the test happens reasonably often ... but not too often. You also want to check only when it would be safe to stop the computation, and that is another thing you must work out for yourself.

The following should help to give you some ideas of how you might apply it to your problem. Hope it helps...

    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();
                    }
                }
            }
        }
    }

Whether you use a stop flag or an interrupt, you will need to periodically check to see whether a thread has been signalled to stop.

You could give them access to eachother, or a callback to something that had access to both so it could interrupt the other. Consider:

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);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!