使用ExecutorService,解决多任务同时进行,并等待全部任务完成合并数据
一、ExecutorService使用
刚好做项目的时候碰到类似的需求记录一下,具体代码不方便展示用了网上的代码,底下代码是用网上代码修改的,可不可以运行没调试过,只提供大概思路和解决网上代码的问题,网上很多使用底下这种形式创建ExecutorService,但是阿里的编码规范并不推荐这样创建线程池
ExecutorService exc= Executors.newFixedThreadPool(10);
推荐使用一下方式创建ExecutorService
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
//创建线程池
ExecutorService exc = new ThreadPoolExecutor(searchKeyTypes.length, searchKeyTypes.length, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), namedThreadFactory);
其中ThreadPoolExecutor的构造方法如下:
publicThreadPoolExecutor(intcorePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit
unit,
BlockingQueue<Runnable>
workQueue,
ThreadFactory
threadFactory,
RejectedExecutionHandler
handler)
具体各个参数对线程池的影响可以参考https://blog.csdn.net/jubaoquan/article/details/79198780
二、Future使用
在并发编程中,我们经常用到非阻塞的模型,在之前的多线程的三种实现中,不管是继承thread类还是实现runnable接口,都无法保证获取到之前的执行结果。通过实现Callback接口,并用Future可以来接收多线程的执行结果。Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。
//申明数据回调处理类List<Future<JSONObject>>
List<Future<JSONArray>> futures = new ArrayList<>();
三、功能实现
AAAThreadHttpRequest
public class AAAThreadHttpRequest
{
//首页返回所需的参数和接口,电影接口
//热门电影
private String hotfilmUrl = "http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=1&limit=30&sr=1";
//热门电视剧
private String hotdianshijuUrl = "http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=2&limit=5&sr=2";
//热门动漫
private String hotanimationUrl = "http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=4&limit=5&sr=3";
//第一个分段数据
private String segmentOneUrl ="http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=7&limit=6&sr=5";
//淘宝客
public LinkedList<JSONObject> ShiPinThreadHandle() throws JSONException, IOException, InterruptedException, ExecutionException
{
//组合线程请求参数
String[] urlList = new String[]{hotfilmUrl,hotdianshijuUrl};
//创建线程名
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
//创建线程池
ExecutorService exc = new ThreadPoolExecutor(urlList .length, urlList .length, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), namedThreadFactory);
//申明数据回调处理类List<Future<JSONObject>>
List<Future<JSONObject>> futures = new ArrayList<Future< JSONObject>>();
for (String url : urlList) {
//申请单个线程执行类
ShiPinThreadHandleRequest call =new ShiPinThreadHandleRequest(url);
//提交单个线程
Future< JSONObject> future = exc.submit(call);
//将每个线程放入线程集合, 这里如果任何一个线程的执行结果没有回调,线程都会自动堵塞
futures.add(future);
}
//所有线程执行完毕之后会执行下面的循环,然后通过循环每个个线程后执行线程的get()方法每个线程执行的结果
for (Future< JSONObject> future : futures) {
//这边就能获取返回的数据集 剩下根据自己想要的业务逻辑自行编写
JSONObject json= future.get();
}
//关闭线程池
exc.shutdown();
//这里由于我直接将返回结果放入到单利中缓存了,所有返回null
return null;
}
Callable方法
线程执行者,我们的数据将在这个类的构造函数里面执行,这个类自带了回调函数。当执行结果返回时会通过它自带的回调将请求结果反馈给Future。
Callable执行代码类
public class ShiPinThreadHandleRequest implements Callable<JSONObject> {
private String url;
public ShiPinThreadHandleRequest(String url) throws JSONException, IOException {
//这边其实就是为了传入相关参数,不要在这边直接执行业务你要异步的业务,不然还是同步运行你要的业务
this.url=url;
}
//数据回调
public JSONObject call() throws Exception {
//随便写的,这边就执行你要的业务逻辑,然后返回你要的结果
JSONObject result = HttpUtil.doPost(this.url)
return result;
}
}
结论
虽然自己用Thread写线程也可以实现上面的效果,但是比较麻烦,用上面的方法可以简化不少代码