直接看下面的实验,注释详细:
package com.tbc.java;
import java.util.ArrayList;
import java.util.Date;
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.FutureTask;
public class FutureTaskAndExecutor {
/**
* 个人对FutureTask<T> 的理解: FutureTask<T>从字面上可以理解为:异步任务类。 FutureTask<T>好比一个Map,
* FutureTask<T> 中存放的是任务和该任务结束后返回的结果。可以理解为一个键值对(任务,任务的结果)
* 当任务 加入到FutureTask的对象的时候 任务的结果此时为空,另外FutureTask的一个对象只能一次性添加一个任务。
* 这个任务可以理解为实现Callable接口的类对象,要实现Callable接口的call方法,也就是说我们可以把我们要做的操作放在call方法里。
* FutureTask<T>中的泛型指的是 call方法的返回值的实际类型即 return sum中sum 的类型。
* FutureTask中有个get()方法,当调用该方法时,获取到的值是 call方法中返回的值,
* get()方法只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。
*
*
* 自己的疑问:我在下面做了一个实验,做了一个for循环验证了get()方法确实是阻塞的,既然是一直阻塞的,那么将get放在主线程中调用,不会出现问题吗?
* 这个get到底如何调用才是比较好的方法呢?本人尚未理解透彻,若有不通见解,请留言评论。
*/
/**
* 本例子中加入了线程池的操作,将异步任务加入到线程池,将一些耗时的操作放入线程中操作,主线程还可以做些别的事情
*/
public static void main(String[] args) {
List<FutureTask<Integer>> list =new ArrayList<FutureTask<Integer>>();
/**
* 创建线程池,线程池的大小和List.size没有啥必然的关系,一般的原则是<=list.size,多出来浪费不好
*/
ExecutorService exec = Executors.newFixedThreadPool(5); //创建线程池,线程个数为5个
for(int i =0; i <10; i++) {
/**
* 创建对象
*/
FutureTask<Integer> ft =new FutureTask<Integer>(new GetSum(i));
/**
* 添加到list,方便后面取得结果
*/
list.add(ft);
/**
* 一个个提交给线程池,当然也可以一次性的提交给线程池,exec.invokeAll(list);
*/
exec.submit(ft);
}
// 开始统计结果
Integer total = 0;
for(FutureTask<Integer> ft : list)
{
try
{
System.out.println("在get执行前,total:-----》"+total);
System.out.println("在get执行前,时间:-----》"+new Date());
total = total + ft.get();
System.out.println("在get执行后,total:------》"+total);
System.out.println("在get执行后,时间:------》"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
// 处理完毕,一定要记住关闭线程池,这个不能在统计之前关闭,因为如果线程多的话,执行中的可能被打断
exec.shutdown();
System.out.println("多线程计算后的总结果是:" + total);
}
}
class GetSum implements Callable {
private Integer total;
private Integer sum = 0;
public GetSum(Integer total)
{
this.total = total;
}
public Object call() throws Exception
{
sum=total+1;
System.out.println(Thread.currentThread().getName() + " sum:" + sum);
for (int i = 0; i < 1500000000L; i++) {
}
return sum;
}
}