java - 有没有比使用 CountDownLatch 更好的等待两个线程完成任务的方法?

标签 java multithreading locking

我的要求是在启动依赖作业之前等待两个线程完成执行。

为了做到这一点,我可以创建一个 CountDownLatch 和一个 Waiter Thread 来等待 CountDownLatch 变为零。一个限制是我不能使用主线程来等待两个线程完成。主线程继续执行其他任务。

这东西确实有用。但是,与可靠的设计相比,我对此有一种解决方法。

我的问题如下:

  1. 当前方法有哪些明显缺陷?例如杂散信号
  2. 您会推荐哪种设计?

我当前的代码:

class Waiter implements Runnable {
    private CountDownLatch latch; 

    Waiter (CountDownLatch latch){
        this.latch = latch;
    }

    @Override
    public void run() {
        System.out.println("Waiter Started running..." + latch.getCount());

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Waiter ready to trigger Next Job!");
    }
}

class Processor implements Runnable {
    private CountDownLatch latch; 

    Processor (CountDownLatch latch){
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        latch.countDown();
    }
}

public class CountDownLatchDemo {
    public static void main (String[] args) throws InterruptedException{
        CountDownLatch latch = new CountDownLatch(2);

        ExecutorService executor = Executors.newFixedThreadPool(2);
        for (int i=0; i< 2; i++){
            executor.submit(new Processor(latch));
        }

        ExecutorService waitExecutor = Executors.newFixedThreadPool(2);
        waitExecutor.submit(new Waiter(latch));

        Thread.sleep(3000);
        executor.shutdown();
        waitExecutor.shutdown();
        System.out.println("Keep doing other things! Sleep here is just for help you run this code for test!");
    }
}

最佳答案

CountDownLatch 是适合您任务的解决方案。但 Java 8 提供了另一种选择——CompletableFuture。您可以为您的任务创建两个这样的 futures,然后使用其中一种方法等待 futures 完成并异步执行其他操作。例如:

// Submit Task 1
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
    }
    System.out.println("Task 1 completed");
    return 5;
});
// Submit Task 2
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
    }
    System.out.println("Task 2 completed");
    return 7;
});
// This call will create a future that will wait for f1 and f2 to complete
// and then execute the runnable
CompletableFuture.allOf(f1, f2).thenRun(() -> {
    System.out.println("Both completed");
});

所有这些调用都将异步处理,您的主线程将继续运行。如果您在第三个任务中需要前两个任务的结果,您可以使用 thenAcceptBothAsync() 而不是 allOf():

f1.thenAcceptBothAsync(f2, (a, b) -> System.out.println("Result = " + (a + b)));

CompletableFuture 中有很多方法可以让您创建异步执行任务链。 JVM 使用默认的 ForkJoinPool 来执行它们,但您可以提供自己的 Executor 来完成您的 future 并用它们做很多其他有用的事情。

关于java - 有没有比使用 CountDownLatch 更好的等待两个线程完成任务的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39546565/

相关文章:

java - 构建 Maven 时如何覆盖远程资源?

java - Sun 对 Clojure 的态度如何?

python - 用线程 boost python

java - 在 Java 中使用 smartcardio 在 Raspberry Pi 上使用多个 NFC ACR122U 设备

c++ - 我是否需要通过锁来保护对 Boost MultiIndex 索引(索引本身)的访问?

c# - 加载外部 app.config 会锁定它吗?

java - CELL_TYPE_STRING 无法解析或不是字段

java - 为什么 handleMessage 在 ui 线程中运行而我使用后台线程循环器创建处理程序?

java - 当我在 JPA 代码中设置锁时,它们是在代码中还是在 DBMS 中强制执行?

java - Java boolean 值是 "wrong"吗?