最近好好的研究了下future的使用,使用future,callable的作用主要在于异步计算结果并返回,是用于解决并发的方法,以下为我做的一些简单测试,首先定义一个类(可用于封装future的计算结果),
public class Result {
private Integer code;
private String msg;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
在定义一个方法实现callable接口
public class threadResult implements Callable<Result>{
private String name;
private int age;
public threadResult() {
super();
}
public threadResult(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Result call() throws Exception {
Result res=new Result();
res.setCode(age);
res.setMsg(name);
System.out.println("call执行时间======="+System.currentTimeMillis()+"name"+name+"=======age"+age);
// Thread.sleep(2000);
return res;
}
然后是我的测试类:
测试方法一
public void doThread(){
try{
// FutureTask<Result> futureTask = new FutureTask<Result>(new threadResult());
// ExecutorService executor = Executors.newFixedThreadPool(1);//使用线程池
ExecutorService executor=new ThreadPoolExecutor(2,2,1000, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1),new ThreadPoolExecutor.DiscardOldestPolicy());
//FutureTask<Result> future =(FutureTask<Result>) executor.submit(new threadResult());
Future<Result> future=executor.submit(new threadResult("张三",23));
Result res=future.get();
System.out.println(res.getCode());
System.out.println(res.getMsg());
executor.shutdown();
}catch(Exception e){
e.printStackTrace();
}
}
future的工作流程,如上executor.submit 此处相当于从线程池中取出一个线程然后执行,(new threadResult("张三",23))这一部分相当是调用threadResult的有参构造方法,然后默认会去调用call进行计算,计算完以后会把结果返回给future,输出的结果如下
call执行时间=======1471530865285name张三=======age23
23
张三
当然也可以调用无参的,结果就变成
call执行时间=======1471530946543namenull=======age0
0
null
测试方法二:
public void doThread2(){
try{
ExecutorService executor = Executors.newFixedThreadPool(3);//使用线程池
for(int i=0;i<10;i++){
Future<Result> future=executor.submit(new threadResult("hello word"+i,i));
Result res=future.get();
System.out.println(res.getCode()+"=================="+System.currentTimeMillis());
System.out.println(res.getMsg()+"=================="+System.currentTimeMillis());
}
}catch(Exception e){
e.printStackTrace();
}
}
这个其实也没什么特别的地方,这边使用的是固定大小线程池,运行时最大会有三个线程同时运行
测试方法三:
public void doThread3(){
try{
List<Future<Result>> futures=new ArrayList<Future<Result>>();
ExecutorService executor = new ThreadPoolExecutor(2,2,1000, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1),new ThreadPoolExecutor.DiscardOldestPolicy());//使用线程池
for(int i=0;i<10;i++){
futures.add(executor.submit(new threadResult("hello word"+i,i)));
}
executor.shutdown();
while(true){
if(futures.size()==0){;break;}
System.out.println(1);
for(Future<Result> future:futures){
Result res=future.get();
System.out.println(res.getCode()+"=================="+System.currentTimeMillis());
System.out.println(res.getMsg()+"=================="+System.currentTimeMillis());
}
System.out.println(2);
}
System.out.println(3);
}catch(Exception e){
e.printStackTrace();
}
}
执行结果如下:
1
call执行时间=======1471532412386namehello word0=======age0
0==================1471532412386
hello word0==================1471532412386
call执行时间=======1471532412386namehello word9=======age9
call执行时间=======1471532412386namehello word1=======age1
1==================1471532412386
hello word1==================1471532412386
可以看出整个执行,123的三个输出语句之打印了一个1,说明了这个方法一执行,结果停在了for循环里面,为什么会这样?有必要好好解释一下,首先我这边定义的是一个最大线程数为2,任务阻塞列表数量为1,且超出部分的任务会销毁旧任务的线程池,然后我们看第一个for循环,循环10次,相当于建立10个线程去处理,但我只有两个线程可以用,所以第一次循环和第二次循环分别是被定义的两个线程拿去执行了,但第三次循环的时候,两个线程还没运算结束,所以第三个任务就进了阻塞列表,在之后由于没有空闲的线程,456789次循环的全部把上一次的销毁了,结果最后阻塞列表里面留下了第10次任务(所以可以看到输出了9),这边091的顺序是随机的,可以看到他们的执行时间也是一样的。
在说说为什么会停在for循环里面的,上面说到后来的任务把前面的任务都销毁了,只剩下019,事实上future要到调用get方法的时候才会去取结果,而get方法再调用时会将线程阻塞,值得取到值为止,由于第三次循环的任务被销毁了,所以get在第三次调用时就取不到值了,也就一直停在那了,这就是为什么01能正常输出,9没了(早就卡在那边了)。如果你debug一下就很清楚的可以看懂了。
转载于:https://blog.51cto.com/11745766/1840158