【Java】CompletionService 使用

使用线程池的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


这便是CompletionService的用途,方便我们获取每一次异步得到的结果。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值