如何在任何一个线程完成后终止所有其他正在运行的线程 [英] How to terminate all other running threads after any of one thread is finish

查看:154
本文介绍了如何在任何一个线程完成后终止所有其他正在运行的线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:我有一个并行开始循环的线程集合。首先退出任何线程后,必须终止所有其他正在运行的线程。这是我尝试过但它不起作用。任何帮助表示赞赏。

Problem: I have collection of threads start in a loop parallelly. After exiting anyone of thread first ,all other running threads must be terminated. This is what I tried but it doesn't work. Any help is appreciated.

public class ThreadsMain {

    public static void main(String[] args) {
        int SIZE = 3;
        Thread t[] = new Thread[SIZE];

        for (int i = 0; i < SIZE; i++) {
            myThreads th = new myThreads();
            t[i] = new Thread(th);
            t[i].start();

        }

    }
}


推荐答案

这是一种方法,使用内部锁实现同步器,并使用中断来取消未完成的任务。数据结构使用户线程阻塞,直到生产者提交了结果,然后取消其他工作线程。

Here is one way to do it, with a synchronizer implemented with intrinsic locks, and using interruption to cancel the unfinished tasks. The data structure makes a consumer thread block until a producer has submitted a result, then it cancels the other worker threads.

这是一个玩具示例,请参阅最后的链接,了解实际操作方法。

This is a toy example, see the link at the end for the real-world way to do this.

首先,这是一个接受结果的线程安全数据结构,它允许线程注册为侦听器,并在提交结果后中断它们:

First, here's a threadsafe data structure that accepts results, it allows threads to register as listeners and interrupts them once it has a result submitted to it:

class MyQueue<T> {
    private java.util.List<T> results = new java.util.ArrayList<T>();
    private java.util.List<Thread> listeners = new java.util.ArrayList<Thread>();

    public synchronized void put(T o) {
        results.add(o);
        notifyAll();
        for (Thread listener : listeners) {
            listener.interrupt();
        }
    }

    public synchronized T take() throws InterruptedException {
        while (results.size() == 0) {
            wait();            
        }
        return results.remove(0);
    }

    public synchronized void addListener(Thread t) {
        listeners.add(t);
    }
}

(我不喜欢这个班级知道如此很多关于听众但我不想过度思考玩具的例子。)

(I don't like having this class know so much about the listeners but I don't want to overthink a toy example either.)

等待方法释放锁并使调用线程处于休眠状态,直到发出通知为止(或者它可以随意停止等待)。它使用结果列表的size属性来了解提交结果的时间。假设因为一个线程停止等待你可以推断出当前状态的某些东西是不安全的,一旦线程重新获取锁定它就需要检查当前状态实际是什么。有关等待工作的更多信息,请参阅本教程

The wait method releases the lock and makes the calling thread go dormant until a notification occurs (or it can just stop waiting arbitrarily). It uses the size property of the results list to know when a result has been submitted. It's not safe to assume that because a thread stopped waiting that you can infer something about the current state, once the thread reacquires the lock it needs to check what the current state actually is. For more about how wait works see this tutorial.

这是一个计算结果的任务(在迭代之间休眠,这样这些线程可以运行一段时间):

Here's a task that calculates a result (sleeping between iterations just so these threads can run for a while):

class FibTask implements Runnable {

    private final MyQueue<BigInteger> queue;
    private final int n;
    private long sleepTime;

    public FibTask(int n, long sleepTime, MyQueue<BigInteger> queue) {
        this.n = n;
        this.sleepTime = sleepTime;
        this.queue = queue;
    }

    @Override public void run() {
        BigInteger a = BigInteger.valueOf(0);
        BigInteger b = BigInteger.valueOf(1);
        int i = 0;
        try {
            while (!Thread.currentThread().isInterrupted() && i < n) {
                i = i + 1;
                BigInteger temp = a;
                a = b;
                b = a.add(temp);
                Thread.sleep(sleepTime);
            }    
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        if (!Thread.currentThread().isInterrupted()) {
            queue.put(b);
        }
    }
}

请注意上面的代码中如何Runnable需要知道中断它的企图。中断是合作的,任务负责决定何时检测中断和处理终止过程。

Notice in the code above how the Runnable needs to be aware of attempts to interrupt it. Interruption is cooperative, the task is responsible for deciding when to detect interruption and for handling the termination process.

此外,如果任务涉及IO,则在某些情况下中断不会工作,你必须关闭套接字,请参阅这篇文章,以获得更多有关此问题的讨论。

Also if a task involves IO then in some cases interruption doesn't work and you have to close the socket, see this article for more discussion of this.

这是运行线程并获得结果的主程序。 MyQueue类已经完成了大部分工作,所以这不需要做太多:

Here's the main program that runs the threads and gets the result. The MyQueue class is already doing most of the work so this doesn't have to do much:

class Completion {
    public static void main(String ... args) throws Exception {
        MyQueue<BigInteger> queue = new MyQueue<BigInteger>();
        Thread t1 = new Thread(new FibTask(10, 1000L, queue));
        Thread t2 = new Thread(new FibTask(20, 10000L, queue));
        Thread t3 = new Thread(new FibTask(25, 50000L, queue));
        queue.addListener(t1);
        queue.addListener(t2);
        queue.addListener(t3);
        t1.start();
        t2.start();
        t3.start();
        System.out.println(queue.take());
    }
}

请注意,这不是一场公平竞赛,因为线程的开始是如何交错的,以后的线程处于劣势。将任务提交给预先初始化线程池的执行程序将确保启动线程的时间不会导致延迟。

Be aware this isn't a fair race because of how the threads' starts are staggered, later threads are at a disadvantage. Submitting tasks to an Executor that initializes a threadpool up front would make sure that the time to start a thread didn't cause a delay here.

为了更好的方式使使用像Executors和Futures这样的java.util.concurrent特性,请参阅 ExecutorCompletionService的API文档

For a better way that makes use of java.util.concurrent features like Executors and Futures, see the example given in the API documentation for ExecutorCompletionService.

这篇关于如何在任何一个线程完成后终止所有其他正在运行的线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆