wait for all threads to finish using ExecutorService

问题引出:

使用线程池,怎么阻塞等待所有线程执行完成后,才能继续走下面的逻辑?

使用awaitTermination只能阻塞等待定时时间,超过该时间后,主线程不再阻塞等待,而线程池中的线程仍会继续运行。

executorService.shutdown();
boolean taskCompleted = executorService.awaitTermination(6, TimeUnit.HOURS);
            if (!taskCompleted) {
                executorService.shutdownNow();
                throw new IllegalStateException("任务超时,未完成!");
}

方法一:

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

official documentation that Long.MAX_VALUE, TimeUnit.NANOSECONDS is equivalent to not having a timeout :

java.util.concurrent package documentation under the Timing section: To wait "forever", you can use a value of Long.MAX_VALUE

方法二:

CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}

try {
  latch.await();
} catch (InterruptedException E) {
   // handle
}

and within your task (enclose in try / finally)

latch.countDown();

该方法由一个弊端是:需要提前知道totalNumberOfTasks

方法三:

You can use Lists of Futures, as well:

List<Future> futures = new ArrayList<Future>();
// now add to it:
futures.add(executorInstance.submit(new Callable<Void>() {
  public Void call() throws IOException {
     // do something
    return null;
  }
}));

then when you want to join on all of them, its essentially the equivalent of joining on each, (with the added benefit that it re-raises exceptions from child threads to the main):

for(Future f: this.futures) { f.get(); }

方法四:

you can do it with CompletableFuture:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

 转载自:How to wait for all threads to finish, using ExecutorService?

### C++ 条件变量 `notify_all` 和 `wait_for` 的用法及区别 #### 一、`notify_all` 的定义与作用 `std::condition_variable::notify_all()` 是用于唤醒所有正在等待该条件变量的线程的方法。当调用此方法时,所有因调用 `wait` 或 `wait_for` 而阻塞的线程都会被唤醒并尝试获取互斥锁[^1]。 其典型使用场景如下: - 当某个共享资源的状态发生改变,并且多个线程可能对此状态感兴趣时,可以使用 `notify_all` 唤醒所有等待的线程。 - 如果不确定哪个具体线程应该被唤醒,则通常会选择通知所有线程让它们自行判断是否满足继续执行的条件。 示例代码展示如何使用 `notify_all`: ```cpp #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::condition_variable cv; std::mutex mtx; bool ready = false; void worker(int id) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); std::cout << "Thread " << id << " is running\n"; } int main() { const int num_threads = 5; std::vector<std::thread> threads; for (int i = 0; i < num_threads; ++i) { threads.emplace_back(worker, i); } { std::lock_guard<std::mutex> lock(mtx); ready = true; } cv.notify_all(); for (auto& t : threads) { t.join(); } return 0; } ``` --- #### 二、`wait_for` 的定义与作用 `std::condition_variable::wait_for(std::unique_lock<std::mutex>& lock, const Rep& rel_time)` 方法允许线程在一个指定的时间范围内等待条件变量。如果超时时间到达而条件仍未满足,则线程会自动退出等待状态。 它适用于以下情况: - 需要设置最大等待时限来防止无限期挂起的情况。 - 可能存在虚假唤醒(spurious wakeup),即即使没有显式的 `notify_*` 调用也可能导致线程醒来,在这种情况下可以通过超时机制减少不必要的计算开销。 下面是一个简单的例子说明如何利用 `wait_for` 实现带超时功能的通知操作: ```cpp #include <iostream> #include <thread> #include <chrono> #include <mutex> #include <condition_variable> std::condition_variable cv; std::mutex mtx; bool data_ready = false; void consumer() { std::unique_lock<std::mutex> lck(mtx); if (!cv.wait_for(lck, std::chrono::seconds(2), [] { return data_ready; })) { std::cout << "Timeout occurred before the condition was met.\n"; } else { std::cout << "Data has been processed successfully!\n"; } } void producer() { std::this_thread::sleep_for(std::chrono::milliseconds(3000)); { std::lock_guard<std::mutex> lck(mtx); data_ready = true; } cv.notify_one(); // Notify one waiting thread that the work can proceed. } int main() { std::thread c(consumer); std::thread p(producer); p.join(); c.join(); return 0; } ``` --- #### 三、两者的主要差异对比 | 特性 | `notify_all` | `wait_for` | |-------------------------|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | **目的** | 唤醒所有处于等待状态下的线程 | 让当前线程在一定时间内保持休眠直到特定事件触发或者达到设定的最大延迟 | | **适用范围** | 多个消费者竞争同一资源的情况下 | 对于那些希望避免永久阻塞以及能够容忍一定程度不确定性延迟的应用程序非常有用 | | **性能影响** | 可能引起额外的竞争压力因为一下子激活了很多潜在候选者 | 提供更精确控制何时重新评估条件从而优化整体吞吐量 | --- ### 结论 综上所述,选择合适的 API (`notify_all`, `notify_one`) 或者附加参数化版本(`wait_until`, `wait_for`)取决于实际需求。对于大多数简单同步问题来说,单独依靠 `notify_one` 就足够;然而面对复杂多变环境则推荐采用更加灵活精细的方式比如结合定时器一起使用的 `wait_for`.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值