有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程java多线程运行,当一个线程找到解决方案时停止线程

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

在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的类中,我在试图找出如何使其成为一个线程时遇到了困难,因此一旦其中一个线程找到了解决方案,所有线程都将停止。最终发生的情况是,要么其他线程继续运行,有时这些线程会相互中断并相互写入


共 (3) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

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

    此示例演示如何等待线程完成

    你需要确保你的行为是可中断的^本例中所示的{}默认情况下是可相互访问的。有关更多信息,请参见oracle docs

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

  3. # 3 楼答案

    您必须中断这些线程(并在runnable中处理中断)。我也不确定你是否应该使用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. 创建一个计数为1的CoundDownLatch屏障
    3. 您提交任务,任务完成后,调用cdl.countDown();将计数器从1减少到0
    4. 父线程等待CountDownLatch减少到0-您可能应该使用第二个版本(例如,阻塞到5分钟)

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

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

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