用户工具

站点工具


分享:技术:多线程:java异步回调

java异步回调

理解

主线程有多个动作,比较耗时,如果主线程是单线程执行,会阻塞比较长时间才能完成。

异步指的是:如果多个动作是可以并行同时去做的,则可以采用多线程异步发起多个动作的调用。

回调指的是:多个动作多线程异步执行完的结果,还可以传送到主线程中,继续下面的操作。

用到的类

  1. ExecutorService接口:定义线程池大小,执行FuruteTask
  2. Callable接口:真正异步执行的内容,可以返回执行结果
  3. FuruteTask类:指定Callable对象,并在主线程中获取异步执行结果

代码示例

ThreadController.java
	/**
	 * 测试AsynCallback 异步回调
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/testAsynCallback",produces="application/json")
	public @ResponseBody String testAsynCallback() {
		logger.info("测试AsynCallback,开始===");
 
		/**
		 * 进行异步任务列表
		 */
		List<FutureTask<Integer>> futureTasks = new ArrayList<FutureTask<Integer>>();
		/**
		 * 线程池 初始化3个线程 和JDBC连接池是一个意思 实现重用
		 */
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		long start = System.currentTimeMillis();
		/**
		 * 类似与run方法的实现 Callable是一个接口,在call中手写逻辑代码
		 */
		Callable<Integer> callable = new Callable<Integer>() {
			@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<Integer> futureTask = new FutureTask<Integer>(callable);
			futureTasks.add(futureTask);
			/**
			 * 提交异步任务到线程池,让线程池管理任务
			 * 由于是异步并行任务,所以这里并不会阻塞
			 * 注意:一旦提交,线程池如果有可用线程,马上分配执行!
			 */
			executorService.submit(futureTask);
		}
		logger.info("将5个任务提交到线程池结束!");
		logger.info("从异步任务列表中获取所有回调开始!");
		int count = 0;
		for (FutureTask<Integer> 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秒

分享/技术/多线程/java异步回调.txt · 最后更改: 2017/05/18 07:20 由 gxx