https://www.cnblogs.com/qq931399960/p/15555152.html中的实现,无论是join还是futuretask都会阻塞主线程,影响效率
JDK8出现了一个新的类CompletableFuture,可以很容易的实现异步回调,使用该类实现订餐外卖
private static Logger logger = LoggerFactory.getLogger(OrderMealPlatformJDK8.class); static Boolean merchantFinish = null; static Boolean courierFinish = null; public static void main(String[] args) { try { CompletableFuture.runAsync(() -> { try { logger.info("起锅烧油"); logger.info("炒菜"); // 5s炒菜时间 Thread.sleep(5000); logger.info("盛饭"); logger.info("打包"); merchantFinish = true; } catch (Exception e) { logger.error("", e); } if (courierFinish != null) { sendMeal(merchantFinish, courierFinish); } }); CompletableFuture.runAsync(() -> { try { logger.info("抢单"); logger.info("规划路线"); // 3s赶路时间 Thread.sleep(3000); logger.info("赶路"); logger.info("到店"); courierFinish = true; } catch (Exception e) { logger.error("", e); } if (merchantFinish != null) { sendMeal(merchantFinish, courierFinish); } }); } catch (Exception e) { logger.error("", e); } logger.info("继续发布订单消息"); } private static void sendMeal(boolean merchantResult, boolean courierResult) { if (merchantResult && courierResult) { logger.info("快递员开始送餐 。。。"); } else if (merchantResult && !courierResult) { logger.error("外卖员车子被偷了,不能够送餐"); } else if (!merchantResult && courierResult) { logger.error("商家厨师家里临时有事,请假了,做不了饭"); } else { logger.error("外卖员车子被偷,商家厨师请假了 。。。 "); } }
运行结果如下:
18:24:38.425 [ForkJoinPool.commonPool-worker-1] INFO com.demo.order.OrderMealPlatformJDK8 - 起锅烧油 18:24:38.425 [main] INFO com.demo.order.OrderMealPlatformJDK8 - 继续发布订单消息 18:24:38.425 [ForkJoinPool.commonPool-worker-2] INFO com.demo.order.OrderMealPlatformJDK8 - 抢单 18:24:38.429 [ForkJoinPool.commonPool-worker-1] INFO com.demo.order.OrderMealPlatformJDK8 - 炒菜 18:24:38.429 [ForkJoinPool.commonPool-worker-2] INFO com.demo.order.OrderMealPlatformJDK8 - 规划路线
可以发现,这个结果与我们期望的不一致,并且从线程名称可以看出,使用到了默认的ForkJoinPool线程池,该线程池的关闭不受我们控制,解决以上问题,可以使用自定义线程池来处理
private static Logger logger = LoggerFactory.getLogger(OrderMealPlatformJDK8.class); static Boolean merchantFinish = null; static Boolean courierFinish = null; public static void main(String[] args) { ThreadPoolExecutor pool = null; try { pool = new ThreadPoolExecutor(2, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(4)); CompletableFuture.runAsync(() -> { try { logger.info("起锅烧油"); logger.info("炒菜"); // 5s炒菜时间 Thread.sleep(5000); logger.info("盛饭"); logger.info("打包"); merchantFinish = true; } catch (Exception e) { logger.error("", e); } if (courierFinish != null) { sendMeal(merchantFinish, courierFinish); } }, pool); CompletableFuture.runAsync(() -> { try { logger.info("抢单"); logger.info("规划路线"); // 3s赶路时间 Thread.sleep(3000); logger.info("赶路"); logger.info("到店"); courierFinish = true; } catch (Exception e) { logger.error("", e); } if (merchantFinish != null) { sendMeal(merchantFinish, courierFinish); } }, pool); } catch (Exception e) { logger.error("", e); } finally { // 模拟真实使用线程池情况,如果直接在这里执行shutdownThreadPoolGracefully方法,则main方法会阻塞(原因还不清楚) ThreadPoolRunnable tpr = new ThreadPoolRunnable(pool); Thread closePool = new Thread(tpr); closePool.start(); } logger.info("继续发布订单消息"); } private static void sendMeal(boolean merchantResult, boolean courierResult) { if (merchantResult && courierResult) { logger.info("快递员开始送餐 。。。"); } else if (merchantResult && !courierResult) { logger.error("外卖员车子被偷了,不能够送餐"); } else if (!merchantResult && courierResult) { logger.error("商家厨师家里临时有事,请假了,做不了饭"); } else { logger.error("外卖员车子被偷,商家厨师请假了 。。。 "); } }
class ThreadPoolRunnable implements Runnable { private Logger logger = LoggerFactory.getLogger(ThreadPoolRunnable.class); private ExecutorService pool; public ThreadPoolRunnable(ExecutorService pool) { this.pool = pool; } @Override public void run() { // 如果在main方法的finally中执行该方法,则会出现main方法被阻塞(原因未知),此处模拟 shutdownThreadPoolGracefully(pool); } private void shutdownThreadPoolGracefully(ExecutorService pool) { if (pool == null) { return; } if (!(pool instanceof ExecutorService) || pool.isTerminated()) { return; } try { // 拒绝新任务的提交,并等待所有任务有序的执行完成 pool.shutdown(); } catch (Exception e) { logger.error("", e); } try { // 等待60s使线程池中的任务执行完 if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { // 将鲜橙汁状态设置为STOP,中断所有线程,清空工作队列,取出所有未完成的任务返回给调用者 pool.shutdownNow(); if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { // 再次尝试60s logger.error("线程池未正常执行结束"); } } } catch (Exception e) { pool.shutdownNow(); } // 仍然未关闭 if (!pool.isTerminated()) { try { for (int i = 0; i < 1000; i++) { if (pool.awaitTermination(10, TimeUnit.MILLISECONDS)) { break; } pool.shutdownNow(); } } catch (Exception e) { logger.error("", e); } } } }
运行结果:
18:27:53.856 [main] INFO com.demo.order.OrderMealPlatformJDK8 - 继续发布订单消息 18:27:53.856 [pool-1-thread-2] INFO com.demo.order.OrderMealPlatformJDK8 - 抢单 18:27:53.856 [pool-1-thread-1] INFO com.demo.order.OrderMealPlatformJDK8 - 起锅烧油 18:27:53.859 [pool-1-thread-2] INFO com.demo.order.OrderMealPlatformJDK8 - 规划路线 18:27:53.859 [pool-1-thread-1] INFO com.demo.order.OrderMealPlatformJDK8 - 炒菜 18:27:56.860 [pool-1-thread-2] INFO com.demo.order.OrderMealPlatformJDK8 - 赶路 18:27:56.860 [pool-1-thread-2] INFO com.demo.order.OrderMealPlatformJDK8 - 到店 18:27:58.860 [pool-1-thread-1] INFO com.demo.order.OrderMealPlatformJDK8 - 盛饭 18:27:58.860 [pool-1-thread-1] INFO com.demo.order.OrderMealPlatformJDK8 - 打包 18:27:58.860 [pool-1-thread-1] INFO com.demo.order.OrderMealPlatformJDK8 - 快递员开始送餐 。。。