如何在任何一个线程完成后终止所有其他正在运行的线程

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

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

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

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

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

 class MyQueue { private java.util.List results = new java.util.ArrayList(); private java.util.List listeners = new java.util.ArrayList(); 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); } } 

(我不喜欢让这堂课对听众有太多了解,但我也不想过度思考玩具的例子。)

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

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

 class FibTask implements Runnable { private final MyQueue queue; private final int n; private long sleepTime; public FibTask(int n, long sleepTime, MyQueue 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如何知道中断它的尝试。 中断是合作的,任务负责决定何时检测中断和处理终止过程。

此外,如果任务涉及IO,那么在某些情况下,中断不起作用,您必须关闭套接字,请参阅本文以获得对此的更多讨论。

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

 class Completion { public static void main(String ... args) throws Exception { MyQueue queue = new MyQueue(); 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()); } } 

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

有关使用Executors和Futures等java.util.concurrentfunction的更好方法,请参阅ExecutorCompletionService的API文档中给出的示例。

一个简单的方法,使用synchronized类来处理循环条件:

 class ThreadHandler { static Object lock = new Object(); static boolean finished = false; static void finishThreads() { synchronized(lock) { finished = true; } } static boolean isFinished() { boolean result; synchronized(lock) { result = finished; } return result; } } 

并在你的runnable

 class myThreads implements Runnable { @Override public void run() { while(!ThreadHandler.isFinished()) { } } }