java Guava ListenableFuture实现线程回调功能

   java Future具有局限性。在实际应用中,当需要下载大量图片或视频时,可以使用多线程去下载,提交任务下载后,可以从多个Future中获取下载结果,由于Future获取任务结果是阻塞的,所以将会依次调用Future.get()方法,这样的效率会很低。很可能第一个下载速度很慢,则会拖累整个下载速度。
    Future主要功能在于获取任务执行结果和对异步任务的控制。但如果要获取批量任务的执行结果,从上面的例子我们已经可以看到,单使用 Future 是很不方便的。其主要原因在于:一方面是没有好的方法去判断第一个完成的任务;另一方面是 Future的get方法 是阻塞的,使用不当会造成线程的浪费。第一个问题可以用 CompletionService 解决, CompletionService 提供了一个 take() 阻塞方法,用以依次获取所有已完成的任务。 第二个问题可以用 Google Guava 库所提供的 ListeningExecutorService 和 ListenableFuture 来解决。除了获取批量任务执行结果时不便,Future另外一个不能做的事便是防止任务的重复提交。要做到这件事就需要 Future 最常见的一个实现类 FutureTask 了。Future只实现了异步,而没有实现回调,主线程get时会阻塞,可以轮询以便获取异步调用是否完成。
   在实际的使用中建议使用Guava ListenableFuture来实现异步非阻塞,目的就是多任务异步执行,通过回调的方方式来获取执行结果而不需轮询任务状态。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

public class ListenableTest {

	public static void main(String[] args) {
		ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
		final List<Long> value = new ArrayList<Long>();
		List<ListenableFuture<Long>> futures = new ArrayList<ListenableFuture<Long>>();
		for(long i=1;i<=3;i++){
			// 处理线程逻辑
	        final ListenableFuture<Long> listenableFuture = executorService.submit(new AddCallable(1000000*(i-1)+1,i*1000000));
	        // 回调方法 
	        Futures.addCallback(listenableFuture, new FutureCallback<Long>() {
	            @Override
	            public void onSuccess(Long result) {
	            	value.add(result);
	            }
	            
	            @Override
	            public void onFailure(Throwable t) {
	                t.printStackTrace();
	            }
	        });
	        futures.add(listenableFuture);
		}
		// 阻塞三个线程执行完成
		Futures.allAsList(futures);
		long result = 0 ;
		for(int i=0,n=value.size();i<n;i++){
			result += value.get(i);
		}
		System.out.println("sum:"+result);
		executorService.shutdownNow();
	}
}

/**
 * 累加线程
 * @author 
 * @time 
 */
class AddCallable implements Callable<Long>{
	private long begin ;
	private long end ;
	
	public AddCallable(long begin,long end){
		this.begin = begin ;
		this.end = end ;
	}
	
	@Override
	public Long call() throws Exception {
		long result = 0;
		for(long i=begin;i<=end;i++){
			result += i;
		}
		return result ;
	}
}




猜你喜欢

转载自forlan.iteye.com/blog/2399632