最近好好的研究了下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{ 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{ // FutureTaskfutureTask = new FutureTask (new threadResult()); // ExecutorService executor = Executors.newFixedThreadPool(1);//使用线程池 ExecutorService executor=new ThreadPoolExecutor(2,2,1000, TimeUnit.SECONDS, new ArrayBlockingQueue (1),new ThreadPoolExecutor.DiscardOldestPolicy()); //FutureTask future =(FutureTask ) executor.submit(new threadResult()); Future 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++){ Futurefuture=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> futures=new ArrayList >(); ExecutorService executor = new ThreadPoolExecutor(2,2,1000, TimeUnit.SECONDS, new ArrayBlockingQueue (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 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一下就很清楚的可以看懂了。