• JDK异步回调


    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("外卖员车子被偷,商家厨师请假了 。。。 ");
            }
        }
    View Code

    运行结果如下:

    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 - 规划路线
    View Code

    可以发现,这个结果与我们期望的不一致,并且从线程名称可以看出,使用到了默认的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 - 快递员开始送餐 。。。
  • 相关阅读:
    golang 引用相对路径package
    LiteIDE 在 Windows 下为 Go 语言添加智能提示代码补全
    C#代码实现把网页文件保存为mht文件
    AE开发中关于 “无法嵌入互操作类型.........请改用适用的接口”问题的解决方法
    Windows下visual studio code搭建golang开发环境
    Eclipse配置开发Go的插件——Goclipse
    go语言条件语句 if else
    Go语言基础:method
    GO语言基础之method
    go中的接口
  • 原文地址:https://www.cnblogs.com/qq931399960/p/15589769.html
Copyright © 2020-2023  润新知