8

我有 n 个线程并行运行,每个线程都执行一些自定义逻辑。但是,我的要求是,当任何线程完成执行时,所有其他线程都应该停止执行并返回。

实现这一点的最佳方法是什么?我想通过共享布尔变量来做到这一点。当任何线程完成执行时,它将设置布尔值。所有所有线程都会定期读取此变量并在设置时退出。

此外,我的自定义逻辑是一个无限循环,一旦我知道其他线程已完成执行,我想在当前迭代后停止执行。

这样做的正确方法是什么?

4

3 回答 3

9

使用 anExecutorService及其.invokeAny()方法(注意:还有一个带有超时的版本)。

来自 Javadoc:

执行给定任务,返回已成功完成的任务的结果(即,不抛出异常),如果有的话。

你有你的结果,.shutdown()执行者。

查看Executors课程以获得适合您需求的执行器。

另一个解决方案是ExecutorCompletionService类;在这种情况下,您将.take()代替.invokeAny(), 并且必须一一提交每个任务。而且您还必须保留对您的引用,ExecutorService因为您需要一个作为参数,并且还需要将其关闭。

(注意:如果您不返回结果,请创建实例)Callable<Void>

于 2013-06-18T10:55:09.013 回答
1

我更喜欢使用通用信号量来控制执行,并经常检查线程。

public class MyTask implements Runnable {
    private static volatile boolean isDone = false
    @Override
    public void run() {
        while(true) {
            if (isDone) {
                break;
            }

            // do some calculation, no wait() s

            if (...has result...) {
                isDone = true;
                break;
            }
        }
    }
}

Thread t1 = new Thread(new MyTask());
Thread t2 = new Thread(new MyTask());
Thread t3 = new Thread(new MyTask());
t1.start();
t2.start();
t3.start();

您唯一必须注意的是static volatile boolean变量。静态是因为所有线程都必须访问同一个标志,易失是为了防止 JVM 缓存其数据。如果您不将其标记为易失性,编译器可能会生成这样的字节码,它会优化从字段中读取的方式,使其仅读取该字段一次,并在每次循环执行时使用保存的值。

如果您的任务不同并且您实现了不同的循环,则可以使用任何外部public static volatile boolean字段来保存标志。

该解决方案不依赖于线程的等待状态。您可以检查isDone循环中的多个位置(甚至在每个代码块之前)。如果您保证您的代码将达到退出检查,则无论如何都无需中断线程。

于 2013-06-18T13:23:55.050 回答
0

看,您可以将所有 Thread 对象保存在一个共享的全局数组中,然后在每个任务结束时,您可以调用一个“清理”函数,该函数只获取所有这些对象并对它们执行“中断”调用。这将导致第一个线程完成以完成其余线程的执行。

public class MyMain
{
   public static Thread workers[NUM_WORK];
   public static void main(..)
   {
      MyMain.workers[0] = new Thread(new MyTask0());
      .
      .
      .
      MyMain.workers[n] = new Thread(new MyTaskN());
      //Then start them all..
      // And wait for them unless you want them to die before execution ;)
   }
}

然后在你的其他工人身上

import MyMain;
public class MyTaskI implements Runnable
{
   public void run()
   {
      //Do all the work
      for(Thread t : MyMain.workers)
      {
         // If it is not this thread
         t.interrupt();
      }
   }
}

对不起,如果我犯了任何语法错误。自从我做 Java 以来已经有一段时间了,这个想法是你明白了;)

于 2013-06-18T13:44:20.000 回答