需求:已知三方的地址cookie等信息,用java的URLConnection接口取获取结果,但是只能指定当前页page,不能指定获取结果数,这样要获取所有的查询结果,只好用循环的方式从第一页取到最后一页,然后把结果合并起来,再做接下来的处理
问题:开始是用单线程来处理,但是结果需要20s+才能出来,这显然有点太长了。后来考虑了多线程,用CountDownLatch+Thread的方式,每页用一个线程去获取结果,这样出来是,在不出错的情况下,时间缩短到了3s+。虽然时间少了不少,但是有可能某次调用出现超时异常,这样导致,CountDownLatch最终不能为1,程序阻塞。
解决:用线程池取解决,ExecutorService es = Executors.newCachedThreadPool(),
for(int i = 2;i <= page;i++) {
Future<F2000IF04VO_01> future = es.submit(new ReguCall(i,keyword,cookie));
list.add(future.get());
}
这样写是错误的,因为get方法会导致线程阻塞。
解决思路:应该先将所有的future放到集合里,然后再遍历这个集合取每个future的结果,当然这里ReguCall是Callable的子类,否则如果是Runnable子类的话,则获取不到结果。
for(int i = 2;i <= page;i++) {
Future<F2000IF04VO_01> future = es.submit(new ReguCall(i,keyword,cookie));
futures.add(future);
}
for(int i = 0;i<futures.size();i++) {
reList.addAll(futures.get(i).get().getResult());
}
线程池在submit的时候,就已经调用了线程的run方法执行那个任务的代码了,所以,如果每个任务耗时很短的话,遍历future集合的时候,结果已经出来了,不会造成阻塞(但究竟是结果返回的快,还是循环提交任务的速度快,没有经过实际测试,但结果是速度确实有所提升,而且不会造成Countdownlatch控制不好导致的程序阻塞了)。