盒子
盒子
文章目录
  1. 1. 需求描述
  2. 2. 问题分析与实现
  3. 3. CompletionService源码分析
  4. 4. 代码实现

CompletionService优点及其应用

1. 需求描述

某一图片网站首页有许多图片,渲染时间较长,给用户带来较差体验,为提高用户体验度,图片需缓存且无需等待所有图片全部准备完毕后,进行渲染

2. 问题分析与实现

显而易见,我们可以想到一边获取图片,一边进行渲染,并行操作。但是每张图片获取的时间无法预知,即任务的执行时长不一致,有的可能几毫秒,有的可能几秒, 我们如何才能做到先获取的图片先进行渲染呢?幸好CompletionService适合该场景: 将Executor与BlockingQueue的功能融合在一起,将Callable任务提交给它执行,然后类似队列中的take与poll获取已经完成的任务。

3. CompletionService源码分析

1
2
3
4
5
6
7
8
9
public interface CompletionService<V> {
Future<V> submit(Callable<V> task);

Future<V> take() throws InterruptedException;

Future<V> poll();

......
}

CompletionService唯一实现类: ExecutorCompletionService。 在构建函数中创建一个BlockingQueue保存结果。任务提交后,将任务包装成QueueingFuture(FutureTask的一个子类),任务完成后,调用QueueingFuture的done方法,将结果放入BlockingQueue中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final BlockingQueue<Future<V>> completionQueue;

public ExecutorCompletionService(Executor executor) {
if (executor == null)
throw new NullPointerException();
this.executor = executor;
this.aes = (executor instanceof AbstractExecutorService) ?
(AbstractExecutorService) executor : null;
this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}

public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f)); // 任务包装成QueueingFuture
return f;
}

private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); } // 任务完成后,调用done方法,放入队列
private final Future<V> task;
}

public Future<V> take() throws InterruptedException {
return completionQueue.take();
}

public Future<V> poll() {
return completionQueue.poll();
}
}

4. 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 使用CompletionService实现页面渲染器
*/
public class Renderer {

private ExecutorService executor;

public Renderer(ExecutorService executor) {
this.executor = executor;
}

public void renderPage(CharSequence source) {
List<ImageInfo> info = scanImageInfo(source);
CompletionService<ImageData> completionService = new ExecutorCompletionService<>(executor);

for (final ImageInfo imageInfo : info) {
completionService.submit(() -> {
return imageInfo.downloadImage();
});
}

renderText(source);

try {
for (int i = 0; i < info.size(); i++) {
Future<ImageData> future = completionService.take();
ImageData imageData = future.get();
renderImage(imageData);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
支持一下
扫一扫,支持沈健
  • 微信扫一扫
  • 支付宝扫一扫