JDK非同步回撥
阿新 • • 發佈:2021-11-22
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 = nullView Code; 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 - 規劃路線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 - 快遞員開始送餐 。。。