需求:for循环里面下载视频,并开启多线程来执行下载任务。
如果不做任何处理,多线程为异步的,怎么样才能让他下载完一个视频再下载下一个呢?
方法一(本人采用):使用 CountDownLatch
// 创建拥有100个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(100);
// 创建计数器,初始值数量必须等于线程池数量
CountDownLatch latch = new CountDownLatch(100);
for (int i = 0; i < 5; i++) {
executor.submit(() -> {
// 子线程处理下载任务
doDownLoad();
//线程执行后,计数器减1
latch.countDown();
});
}
//这个是关键代码
// 等待所有子线程的任务执行完毕
//。在主线程中,调用 CountDownLatch.await() 方法阻塞等待所有子线程的任务执行完毕,直到计数器减为 0 才继续执行后续代码。
latch.await();
// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomething...;
方法二:使用 ExecutorService
// 创建拥有 100 个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(100);
List<Callable<Void>> tasks = new ArrayList<>();
for (int i = 0; i < 100; i++) {
tasks.add(() -> {
// 子线程处理任务
doDownLoad();
return null;
});
}
//ExecutorService 中的 invokeAll() 方法可以提交多个 Callable 或 Runnable 任务,并阻塞等待所有任务完成。该方法返回一个 Future 对象列表,可以通过遍历列表获取各个子线程处理任务后的结果。
// 等待所有子线程的任务执行完毕
executor.invokeAll(tasks);
// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomething...
方法三:使用 CompletableFuture 的 allOf() 方法
ExecutorService executor = Executors.newFixedThreadPool(100);
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 子线程处理任务
doDownLoad();
}, executor);
futures.add(future);
}
//allOf() 方法可以用于等待所有 CompletableFuture 对象的计算结果
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomething...;
方法四:手动
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // corePoolSize
5, // maximumPoolSize
0L, TimeUnit.MILLISECONDS, // keepAliveTime, unit
new LinkedBlockingQueue<Runnable>()); // workQueue
AtomicInteger count = new AtomicInteger(5); // 计数器,初始值为 5
for (int i = 0; i < 5; i++) {
executor.execute(() -> {
// 子线程处理任务
doDownLoad();
count.decrementAndGet(); // 计数器减 1
});
}
while (count.get() > 0) {
Thread.sleep(100); // 等待一段时间,避免空转浪费 CPU 资源
}
// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomething...;