Java多线程之ExecutorService.invokeAll()

并发执行任务与结果处理
本文介绍了一个使用Java实现的并发执行多个任务的方法,并通过ExecutorService的invokeAll方法收集所有任务的结果。文中提供了一个示例代码,展示了如何定义任务、执行任务及获取任务结果。

方法说明:

    /**
     * Executes the given tasks, returning a list of Futures holding
     * their status and results when all complete.
     * {@link Future#isDone} is {@code true} for each
     * element of the returned list.
     * Note that a <em>completed</em> task could have
     * terminated either normally or by throwing an exception.
     * The results of this method are undefined if the given
     * collection is modified while this operation is in progress.
     *
     * @param tasks the collection of tasks
     * @param <T> the type of the values returned from the tasks
     * @return a list of Futures representing the tasks, in the same
     *         sequential order as produced by the iterator for the
     *         given task list, each of which has completed
     * @throws InterruptedException if interrupted while waiting, in
     *         which case unfinished tasks are cancelled
     * @throws NullPointerException if tasks or any of its elements are {@code null}
     * @throws RejectedExecutionException if any task cannot be
     *         scheduled for execution
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

 

运行结果可能出现的情况:

  • 全部运行成功
  • 部分运行失败,剩余任务被取消

玩具代码:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

//运行多个任务并处理所有结果
public class Result {
	
	
	private String name;
	private int value;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
	
	public static class Task implements Callable<Result>{

		private String name;
		
		public Task(String name){
			this.name = name;
		}
		
		@Override
		public Result call() throws Exception {
			System.out.printf("%s : Staring \n", this.name);
			try{
				long duration = (long)(Math.random()*10);
				System.out.printf("%s:Waiting %d seconds for results . \n", this.name,duration);
				TimeUnit.SECONDS.sleep(duration);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
			
			int value = 0;
			for(int i=0;i<5;i++){
				value += (int)(Math.random()*100);
			}
			Result result = new Result();
			result.setName(name);
			result.setValue(value);
			System.out.println(this.name+": Ends");
			return result;
		}
		
	}

	

	public static void main(String[] args) {
		
		ExecutorService executor =(ExecutorService)Executors.newCachedThreadPool();
		List<Task> taskList = new ArrayList<>();
		for(int i=0;i<3;i++){
			Task task = new Task(Integer.toString(i));
			taskList.add(task);
		}
		
		List<Future<Result>> resultList = new ArrayList<>();
		
		try {
			//等待所有任务执行完成
			executor.invokeAll(taskList);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		executor.shutdown();
		
		System.out.printf("Main: Printing the results \n");
		for(int i=0;i<resultList.size();i++){
			Future<Result> future = resultList.get(i);
			try{
				Result result = future.get();
				System.out.printf("%s : %s \n",result.getName(),result.getValue());
			}catch(InterruptedException | ExecutionException e){
				e.printStackTrace();
			}
		}

	}

}

 

AbstractExecutorService.invokeAll实现逻辑:

public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks) {
                RunnableFuture<T> f = newTaskFor(t);
                futures.add(f);
                execute(f);
            }
            for (int i = 0, size = futures.size(); i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    try {
                        f.get();
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    }
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

 

 

<think>嗯,用户想了解Java中Callable、ExecutorService和Future的使用示例及原理分析。首先,我得回忆一下这几个类之间的关系。记得Callable和Runnable类似,但可以返回结果和抛出异常,而ExecutorService是用来管理线程池的,Future则用来获取异步任务的结果。 首先,我应该先给出一个简单的示例,展示如何创建Callable任务,提交到ExecutorService,并通过Future获取结果。比如,计算阶乘的任务,这样代码比较直观。代码里需要用到Executors.newFixedThreadPool来创建线程池,然后submit任务,最后用future.get()获取结果。 然后,需要解释每个组件的作用。比如Callable接口的call方法,返回结果;ExecutorService的submit方法返回Future对象;Future的get方法会阻塞直到任务完成。可能还要提到异常处理,比如Callable可以抛出异常,而Future.get()会抛出ExecutionException。 接下来,原理分析部分要说明线程池的工作机制,比如任务提交后进入队列,线程池中的线程从队列中取任务执行。Future的实现原理可能涉及状态的跟踪,比如是否完成、结果存储等。这里可能需要参考引用的资料,比如引用[5]提到Callable需要提交给执行器或包装成FutureTask执行。 还要注意比较Runnable和Callable的不同,比如Callable有返回值,能抛出异常。ExecutorService的优势在于资源管理和任务调度,比如避免频繁创建线程的开销,这点在引用[1]和[3]中都有提到。 用户可能还想知道如何处理多个任务的结果,比如使用ExecutorService.invokeAll方法,并配合Future列表来收集结果。这部分可以加一个示例,比如同时计算多个数的阶乘,展示批量提交和结果获取的过程。 另外,异常处理也是重点,需要说明在Callable中抛出的异常会被包装在Future中,调用get()时才会抛出。可能还需要提到超时处理,使用future.get(timeout, unit)来避免长时间阻塞。 最后,注意事项部分应该涵盖线程池的关闭,避免资源泄漏;Future.get()的阻塞特性;以及合理配置线程池大小。这些内容在引用[2]和[4]中有所涉及。 确保所有代码示例使用正确的语法,比如线程池的创建、任务的提交和结果的获取。同时,要检查引用标记是否正确对应,比如引用[5]提到Callable的执行机制需要ExecutorService或FutureTask。 可能用户的实际需求是希望在自己的项目中实现异步任务处理,所以需要强调这些组件如何配合提高程序性能,以及如何处理返回结果和异常。同时,相关问题部分可以引导用户进一步了解性能优化或高级用法,比如使用CompletionService或者CompletableFuture。</think>### Java中Callable、ExecutorService和Future使用示例及原理分析 #### 一、基础使用示例 ```java // 创建线程池(核心组件) ExecutorService executor = Executors.newFixedThreadPool(3); // 定义Callable任务(可返回结果) Callable<Integer> factorialTask = () -> { int result = 1; for(int i=1; i<=5; i++) result *= i; return result; }; // 提交任务并获取Future对象 Future<Integer> future = executor.submit(factorialTask); // 获取异步计算结果(阻塞方法) Integer result = future.get(); // 返回120 ``` #### 二、核心组件解析 1. **Callable接口** - 定义可返回值的异步任务 - 必须实现`call()`方法,支持泛型返回类型 - 可抛出检查异常(与Runnable的核心区别)[^2] 2. **ExecutorService** - 线程池管理接口(`newFixedThreadPool`/`newCachedThreadPool`) - 任务提交方法: - `submit()`:返回Future对象(支持Callable/Runnable) - `invokeAll()`:批量提交任务[^3] 3. **Future机制** - 异步计算结果容器(状态跟踪:未完成/已完成) - 关键方法: - `get()`:阻塞获取结果(支持超时参数) - `isDone()`:检查任务状态 - `cancel()`:尝试取消任务[^5] #### 三、工作原理示意图 ``` [任务提交] → ExecutorService → [任务队列] ↓ [工作线程] → [执行call()] ↓ [结果封装] → Future对象 ``` #### 四、高级应用场景 **多任务并行处理示例:** ```java List<Callable<String>> tasks = Arrays.asList( () -> fetchDataFromAPI("api1"), () -> processImage("img1.jpg"), () -> calculateStatistics() ); List<Future<String>> futures = executor.invokeAll(tasks); for(Future<String> f : futures) { System.out.println(f.get()); // 顺序获取结果 } ``` #### 五、异常处理机制 ```java try { Future<Object> future = executor.submit(() -> { if(errorCondition) throw new CustomException(); return normalResult; }); Object data = future.get(); } catch (ExecutionException e) { Throwable rootCause = e.getCause(); // 获取原始异常 } ``` #### 六、性能优化建议 1. 根据任务类型选择线程池类型: - CPU密集型:固定大小线程池(n+1) - IO密集型:缓存线程池[^1] 2. 使用`Future.get(long timeout, TimeUnit unit)`避免死锁 3. 配合`CompletionService`实现结果优先处理 #### 七、注意事项 1. **必须关闭线程池**: ```java executor.shutdown(); // 或 executor.shutdownNow(); ``` 2. **避免过度阻塞**: ```java if(future.isDone()) { result = future.get(); } ``` 3. **资源竞争处理**: ```java FutureTask<Integer> futureTask = new FutureTask<>(callable); new Thread(futureTask).start(); // 替代方案 ``` : 线程池类型选择需考虑任务特性 : Callable支持返回值与异常抛出 [^3]: invokeAll实现批量任务提交 : FutureTask的底层实现机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值