====== java异步回调 ======
===== 理解 =====
主线程有多个动作,比较耗时,如果主线程是单线程执行,会阻塞比较长时间才能完成。
异步指的是:如果多个动作是可以并行同时去做的,则可以采用多线程异步发起多个动作的调用。
回调指的是:多个动作多线程异步执行完的结果,还可以传送到主线程中,继续下面的操作。
===== 用到的类 =====
- ExecutorService接口:定义线程池大小,执行FuruteTask
- Callable接口:真正异步执行的内容,可以返回执行结果
- FuruteTask类:指定Callable对象,并在主线程中获取异步执行结果
===== 代码示例 =====
/**
* 测试AsynCallback 异步回调
* @param request
* @return
*/
@RequestMapping(value = "/testAsynCallback",produces="application/json")
public @ResponseBody String testAsynCallback() {
logger.info("测试AsynCallback,开始===");
/**
* 进行异步任务列表
*/
List> futureTasks = new ArrayList>();
/**
* 线程池 初始化3个线程 和JDBC连接池是一个意思 实现重用
*/
ExecutorService executorService = Executors.newFixedThreadPool(3);
long start = System.currentTimeMillis();
/**
* 类似与run方法的实现 Callable是一个接口,在call中手写逻辑代码
*/
Callable callable = new Callable() {
@Override
public Integer call() throws Exception {
Integer res = new Random().nextInt(100);
logger.info("call执行[" + res + "]开始!");
Thread.sleep(3000);
logger.info("call执行[" + res + "]结束!");
return res;
}
};
logger.info("将5个任务提交到线程池开始!");
for(int i=0;i<5;i++){
/**
* 创建一个异步任务
*/
FutureTask futureTask = new FutureTask(callable);
futureTasks.add(futureTask);
/**
* 提交异步任务到线程池,让线程池管理任务
* 由于是异步并行任务,所以这里并不会阻塞
* 注意:一旦提交,线程池如果有可用线程,马上分配执行!
*/
executorService.submit(futureTask);
}
logger.info("将5个任务提交到线程池结束!");
logger.info("从异步任务列表中获取所有回调开始!");
int count = 0;
for (FutureTask futureTask : futureTasks) {
/**
* futureTask.get() 得到我们想要的结果
* 该方法有一个重载get(long timeout, TimeUnit unit) 第一个参数为最大等待时间,第二个为时间的单位
*/
try {
count += futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
logger.info("从异步任务列表中获取所有回调结束!");
long end = System.currentTimeMillis();
logger.info("线程池的任务全部完成:结果为:"+count+",main线程关闭,进行线程的清理");
logger.info("使用时间:"+(end-start)+"ms");
/**
* 清理线程池
*/
executorService.shutdown();
logger.info("测试AsynCallback,结束===");
return "testAsynCallbackOK~";
}
===== 日志输出 =====
2017-05-18 07:16:54,068 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:165] - 测试AsynCallback,开始===
2017-05-18 07:16:54,070 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:189] - 将5个任务提交到线程池开始!
2017-05-18 07:16:54,072 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:203] - 将5个任务提交到线程池结束!
2017-05-18 07:16:54,072 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:204] - 从异步任务列表中获取所有回调开始!
2017-05-18 07:16:54,071 [pool-1-thread-1] INFO [com.gxx.record.web.thread.ThreadController$1:183] - call执行[68]开始!
2017-05-18 07:16:54,071 [pool-1-thread-2] INFO [com.gxx.record.web.thread.ThreadController$1:183] - call执行[84]开始!
2017-05-18 07:16:54,072 [pool-1-thread-3] INFO [com.gxx.record.web.thread.ThreadController$1:183] - call执行[47]开始!
2017-05-18 07:16:57,076 [pool-1-thread-1] INFO [com.gxx.record.web.thread.ThreadController$1:185] - call执行[68]结束!
2017-05-18 07:16:57,076 [pool-1-thread-3] INFO [com.gxx.record.web.thread.ThreadController$1:185] - call执行[47]结束!
2017-05-18 07:16:57,076 [pool-1-thread-2] INFO [com.gxx.record.web.thread.ThreadController$1:185] - call执行[84]结束!
2017-05-18 07:16:57,077 [pool-1-thread-3] INFO [com.gxx.record.web.thread.ThreadController$1:183] - call执行[30]开始!
2017-05-18 07:16:57,076 [pool-1-thread-1] INFO [com.gxx.record.web.thread.ThreadController$1:183] - call执行[57]开始!
2017-05-18 07:17:00,081 [pool-1-thread-1] INFO [com.gxx.record.web.thread.ThreadController$1:185] - call执行[57]结束!
2017-05-18 07:17:00,081 [pool-1-thread-3] INFO [com.gxx.record.web.thread.ThreadController$1:185] - call执行[30]结束!
2017-05-18 07:17:00,082 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:219] - 从异步任务列表中获取所有回调结束!
2017-05-18 07:17:00,082 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:221] - 线程池的任务全部完成:结果为:286,main线程关闭,进行线程的清理
2017-05-18 07:17:00,082 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:222] - 使用时间:6013ms
2017-05-18 07:17:00,082 [http-bio-8080-exec-3] INFO [com.gxx.record.web.thread.ThreadController:228] - 测试AsynCallback,结束===
===== 性能优化分析 =====
主线程阻塞从3*5=15秒,优化到3*(5/3)=6秒