【问题标题】:java multiple threads running , stop threads when one thread finds solutionjava多线程运行,当一个线程找到解决方案时停止线程
【发布时间】:2021-07-05 19:59:34
【问题描述】:

我在尝试停止运行多个线程的程序时遇到问题,所有正在运行的线程都试图找到相同的解决方案,但一旦一个线程找到解决方案,所有其他线程都将停止。

在 main 方法中,我创建了一个线程组并使用 for 循环向其中添加线程并启动它们

ThreadGroup tg = new ThreadGroup("thread group");
Thread th;
for(int i  = 0; i<4; i++){
  th = new Thread(tg, new Runnable(), "Thread " + i)
  th.start();
}

在实现 Runnable 的类中,我在试图弄清楚如何做到这一点时遇到了麻烦,以便一旦其中一个线程找到解决方案,所有线程都会停止。最终发生的是,要么其他线程继续运行,有时线程会相互中断并相互覆盖。

【问题讨论】:

  • 您为每个线程编写代码。不要编写代码来完成您不希望它完成的工作。这样一来,您就不必找到任何特殊的方法来阻止它。

标签: java multithreading java-threads


【解决方案1】:
ThreadGroup tg = new ThreadGroup("thread group");
CountDownLatch latch = new CountDownLatch(1);
AtomicInteger result = new AtomicInteger();
Random random = new Random();
for (int i = 0; i < 4; i++) {
    Thread th = new Thread(tg, () -> {
        try {
            Thread.sleep(random.nextInt(10000));
            result.set(42);
            latch.countDown();
            System.out.println(Thread.currentThread().getName() + " completed task first");
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " was interrupted before it could finish the task");
        }
    }, "Thread " + i);
    th.start();
}
while (latch.getCount() > 0) {
    try {
        latch.await();
    } catch (InterruptedException ignored) {
    }
}
tg.interrupt();
System.out.println("The result is " + result.get());

这个例子展示了如何等待线程完成。

您需要确保您的操作是可中断的。 Thread.sleep 如本例所示,默认情况下是 interrubtible。请参阅oracle docs 了解更多信息。

还请注意,无法保证所有其他线程在完成之前都会被中断。如果您需要确保只处理一个结果,请同步对结果变量的访问并丢弃除第一个结果之外的任何更改。

【讨论】:

    【解决方案2】:

    您必须中断这些线程(并在可运行对象中处理中断)。我也不确定你是否应该使用ThreadGroup - 我记得看到过关于它们的声纳警告。

    您最好使用ExecutorService 并使用CountDownLatch 来执行此操作(这是一种方法):

    ExecutorService es = Executors.newFixedThreadPool(100);
    CountDownLatch cdl = new CountDownLatch(1);
    for (int i = 0; i < 100; ++i) {
      es.submit(() -> {
        Thread.sleep(TimeUnit.SECONDS.toMillis(30)); // + exception handling  
        cdl.countDown();
      });
    }
    cdl.await(); // or await(5, TimeUnit.MINUTES);
    es.shutdownNow();
    

    诀窍是:

    1. 您创建了一个具有 100 个线程池的 ExecutorService
    2. 您创建了一个 CoundDownLatch - 一个障碍 - 计数为 1。
    3. 您提交任务,当他们的工作完成后,调用cdl.countDown(); 将计数器从 1 减少到 0。
    4. 父线程等待 CountDownLatch 减少到 0 - 您可能应该使用第二个版本(例如阻塞到 5 分钟)。

    如果所有 Runnable 都失败,您将不会有结果:要么使用最大等待时间,要么您可以添加另一个 CountDownLatch,这次计数为 100(线程数),@987654332 @ 在try/finally 中,在另一个线程中,中断在cdl 上等待的线程。您也可以循环执行此操作:

    CountDownLatch allCdl = new CountDownLatch(100);
    
    for (;allCdl.getCount() != 0;) {
      if (!cdl.await(60, TimeUnit.SECONDS)) {
        if (allCdl.getCount() == 0) { 
          break;
        }
      }
    }
    

    然而,getCount() 的 javadoc 提到 此方法通常用于调试和测试目的。(请参阅 CyclicBarrier)。不确定这是否是正确的用法。

    【讨论】:

      【解决方案3】:

      在意识到已找到解决方案后,获胜的线程应该向父级发出信号 - 然后向所有其他子级发出信号以停止,或者干脆杀死它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-22
        • 1970-01-01
        • 2015-12-29
        • 2012-12-24
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多