使用线程池的submit方法时,可以返回一个Future,我们可以通过这个Future来获得任务的返回值。那么通常的场景是,我们通过多个任务来获取到了返回值,之后就需要对返回值进行处理,此时我们需要把每一个Future放进一个容器里,然后用一个循环处理。不过这里还是有问题的,我们知道通常的容器是不允许一边读取,一边修改的,会抛出一个ConcurrentModificationExceptoin,一般的容器遍历都是静态的,但是这里的容器却不是,它时时刻刻都有可能被放入一个结果,但是什么时候谁也不知道,而且它有可能是是空的。所以这个容器与以往的场景不同。我们需要支持之前提到的特性。
这其实就是CompletionService的用途,它已经为我们维护了这个队列,它会自动把执行完的任务结果放入队列中,我们可以使用take方法或者poll来获取结果。take在队列为空时会被阻塞,而poll返回null。这样我们编写上述代码就会简单得多,不同再去担心自己维护一个结果的队列的。
下面是一个UI中很常见的例子,异步加载不同的资源,像文本这种的我们可以直接渲染,但是图片这种的,我们需要先下载然后加载,可以让每一个下载异步执行,把结果放入一个队列,再从队列里面拿下好的图片渲染。
package ThreadTest;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class PageRender {
public void rend(Source source){
ExecutorService e = Executors.newFixedThreadPool(10);
CompletionService<Image> ce = new ExecutorCompletionService<Image>(e);
for(String url : source.urls){
ce.submit(new Callable<Image>() {
@Override
public Image call() throws Exception {
return download(url);
}
});
}
rendTxt(source.txt);
for(int i = 0 ; i < source.urls.size(); i++){
try {
Future<Image> future = ce.take();
Image img = future.get();
rendImage(img);
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e1) {
e1.printStackTrace();
}
}
e.shutdown();
}
Image download(String url){
System.out.println("download Image" + url);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Image();
}
void rendTxt(String txt){
System.out.println("rendTxt");
}
void rendImage(Image img){
System.out.println("rendImage");
}
}
public static void main(String[] args) {
PageRender pr = new PageRender();
Source source = new Source();
List<String> list = new ArrayList<>();
for(int i = 0 ; i < 10; i++){
list.add("url " + i);
}
source.urls = list;
source.txt = "Hello";
pr.rend(source);
}
结果:
download Imageurl 0
download Imageurl 2
download Imageurl 3
download Imageurl 1
download Imageurl 4
download Imageurl 5
download Imageurl 6
download Imageurl 7
rendTxt
download Imageurl 9
download Imageurl 8
rendImage
rendImage
rendImage
rendImage
rendImage
rendImage
rendImage
rendImage
rendImage
rendImage