记一次 CompletableFuture 实际使用场景
2023-09-08 本文已影响0人
smart_dev
如果忘记使用方法可参考这篇文章
- 多线程并发执行任务,取结果归集。终极总结:Future、FutureTask、CompletionService CompletableFuture
https://www.cnblogs.com/dennyzhangdd/p/7010972.html- CompletableFuture使用大全,简单易懂
https://juejin.cn/post/6844904195162636295
项目背景
- 在开发短视频下载过程中,发现视频下载时机比较靠后,梳理发现其中有一个原因是我们的普通图片是线性下载的逻辑,即单线程顺序下载。
- 当所有普通图片下载完毕后才会开始展示到页面。
- 为此,想优化图片下载的总共时间,一个可以减少用户在页面等待时间,即不能及时浏览下一张图片;另一个也能为视频缓存在提前一定的时机,争取到更多的时间。
那实际问题就转化成了: 如何去开辟多线程(几个为好这里不讨论)同时需要等待结果都回来
优化方案
采用多线程下载静态图片,并且等全部任务执行完毕后,再继续往下执行。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
public class ImageDownloadManager {
private static final String TAG = ImageDownloadManager.class.getSimpleName();
ExecutorService mExecutor;
public ImageDownloadManager() {
mExecutor = ExecutorManager.xxxx();
}
public List<PictureItem> download(Context context, List<PictureItem> imageList) {
List<PictureItem> copyList = new CopyOnWriteArrayList<>(imageList);
List<CompletableFuture> futureList = new ArrayList<>();
Log.d(TAG, "Start download for all images.");
for (PictureItem item : imageList) {
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(new Supplier<Boolean>() {
@Override
public Boolean get() {
boolean isValid = XXXUtils.preLoadImage(xxxx);
if (!isValid) {
copyList.remove(item);
}
Log.d(TAG, "A download end, isValid:" + isValid + " url: " + xxx);
return isValid;
}
}, mExecutor);
futureList.add(future);
}
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
voidCompletableFuture.join();
Log.d(TAG, "End download for all images. download total count = " + futureList.size()
+ " ,download fail count = " + (imageList.size() - copyList.size()));
return new ArrayList<>(copyList);
}
}
优化结果
整体优化后速度提升了 100% - 140%
- 优化前实时拉取,耗时2.5秒
- 优化后实时拉取 一秒150毫秒 接近1秒
此处本应是日志打印 需要隐藏
项目方案复用需考虑的因素
- 线程个数与任务个数的选择协调
- 任务类型,前台还是后台,是否紧急