首页 > 解决方案 > 加入两个不同的 ExecutorService

问题描述

我想加入两个在 ExecutorService 中执行的线程。

public class CURD {

  public static ExecutorService executorService = Executors.newCachedThreadPool();
  
 @Autowired
 Logging logging;

  public void Update(List<? extends HBase> save, List<? extends HBase> delete) {
        Thread t = new Thread(() -> {
            System.out.println("Started Main Thread...");
            try {
                Thread.sleep(1500);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("End Main Thread...");
        },"Thread-1");

        logging.setPredecessor(t);
        executorService.submit(t);
    }
}

第二类:这个类线程应该等待第一个线程完成。但它不会等待第一个线程完成。我不确定这是否是正确的方法。

请问有人可以让我知道如何加入在 ExecutorService 中执行的两个线程吗?

import static com.demo.executorService;

public class Logging {
   
   private Thread predecessor;
   public void  setPredecessor(Thread t) {
        this.predecessor = t;
    }

  private void loggingInfo() {
      Thread run = new Thread( () ->{
                try {
                    if (predecessor != null) {
                        System.out.println(Thread.currentThread().getName() + " Started");
                        predecessor.join();
                        System.out.println(Thread.currentThread().getName() + " Finished");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            addTask(run);
   }

   public void addTask(Runnable run) {
        System.out.println("Runnable Thread logAround.....");
        CompletableFuture.runAsync((run), executorService).exceptionally(ex -> {
            System.out.println("exception occurred " + ex);
            return null;
        });
    }
}

标签: javamultithreadingparallel-processingjava.util.concurrent

解决方案


如果想在一组线程之间进行同步,可以使用 Java CyclicBarrier类:

一种同步辅助工具,它允许一组线程相互等待以达到共同的障碍点。CyclicBarriers 在涉及固定大小的线程组的程序中很有用,这些线程组必须偶尔相互等待。屏障被称为循环的,因为它可以在等待线程被释放后重新使用。

为此,首先创建CyclicBarrier具有相应数量的对象即:

private final CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_PARIES);

正式地从 Java 文档中可以读到各方是:

在触发屏障之前必须调用 {@link #await} 的线程数

非正式地,各方是必须调用循环屏障并等待的线程数,然后它们才能继续前进。

之后,您需要将屏障实例对象引用传递给应该等待的每个线程,并相应地调用wait barrier.await())。如下所示:

  public void Update(..., CyclicBarrier barrier) {
        Thread t = new Thread(() -> {
            System.out.println("Started Main Thread...");
            try {
                 Thread.sleep(1500);
                 barrier.await(); // <--- wait on the barrier
            } catch (InterruptedException | BrokenBarrierException e) {
                 e.printStackTrace();
             }
            System.out.println("End Main Thread...");
        },"Thread-1");
        ...
    }

对必须等待的其他线程重复此过程。确保参与方的数量( NUMBER_OF_PARIES)与应在循环屏障上等待的线程数相匹配,否则会发生死锁。

现在您正在使用 ,cyclic barrier您可以清理代码的某些部分,例如,您可以删除与类字段相关的所有predecessor逻辑Logging

如果您只想Thread 2等待Thread 1,那么您可以使用CountDownLatch来代替。

一种同步辅助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。CountDownLatch 使用给定的计数进行初始化。由于调用了 countDown() 方法,等待方法一直阻塞,直到当前计数达到零,之后所有等待的线程都被释放,任何后续的 await 调用立即返回。这是一次性现象——计数无法重置。如果您需要重置计数的版本,请考虑使用 CyclicBarrier。

首先创建CountDownLatch只有1计数的对象:

private final CountDownLatch block_thread2 = new CountDownLatch(1);

并将其传递给Thread 2, 并且由于您希望该线程等待Thread 1, 调用block_thread2.await();

      Thread run = new Thread( () ->{
                   try {
                        ....
                        block_thread2.await(); // wait for Thread 2
                   } catch (InterruptedException e) {
                        // deal with it
                   }
     });
            ...

Thread 1添加 wait.countDown();

  public void Update(...) {
        Thread t = new Thread(() -> {
                   System.out.println("Started Main Thread...");
                   try {
                        Thread.sleep(1500);
                        wait.countDown();
                   } catch (InterruptedException e) {
                        // deal with it
            }
            System.out.println("End Main Thread...");
        },"Thread-1");
        ...
    }

所以,以这种方式,Thread 2会等待Thread 1,但Thread 1永远不会等待Thread 2


推荐阅读