大家好,我是君哥。今天分享一道面試題。
面試官:有一個場景,如果一個子任務的執行,要依賴兩個父任務執行完成后才能執行,該怎么設計?
我:可以設置兩個父任務的信號,父任務執行完成后更新信號已完成。子任務被觸發時判斷兩個父任務是否執行完成,只有兩個父任務都執行完成,子任務才會執行。如果條件不滿足,就先掛起。下面是一段示例代碼:
private static AtomicInteger parentTask1 = new AtomicInteger(0);private static AtomicInteger parentTask2 = new AtomicInteger(0);private static Object locker = new Object();public static void main(String[] args) throws InterruptedException { Thread childThread = new Thread(() -> { while (true) { try { synchronized (locker) { if (parentTask1.get() == 1 && parentTask2.get() == 1) { //doSomething break; } locker.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } }); childThread.start(); Thread parentThread1 = new Thread(() -> { parentTask1.incrementAndGet(); synchronized (locker){ locker.notifyAll(); } }); parentThread1.start();}
父任務執行完成后喚醒子任務。
面試官:有其他方法嗎?
我:也可以使用 CompletableFuture,使用任務依賴來控制任務執行,下面是一個示例代碼:
CompletableFuture<Boolean> parentTask1 = CompletableFuture.supplyAsync(() -> { System.out.println("doParentTask1"); return true;});CompletableFuture<Boolean> parentTask2 = CompletableFuture.supplyAsync(() -> { System.out.println("doParentTask2"); return true;});CompletableFuture childTask = CompletableFuture.allOf(parentTask1, parentTask2);childTask.thenApply(c -> { try { if (parentTask1.get() && parentTask2.get()){ System.out.println("doChildTask"); } } catch(Exception e) { e.printStackTrace(); } finally { System.out.println("child task do error"); } return c;});childTask.join();
面試官:那在分布式場景或集群環境下,前面說的方案可以解決問題嗎?
我:分布式場景或者集群環境下,肯定是不能使用上面的線程調度方案的,因為多個任務可能跑在不同進程里。
面試官:現在開源的分布式任務調度框架有很多,比如 xxl-job、PowerJob,有這個場景相關的調度方案嗎?
我:目前的任務調度框架支持子任務配置,但是還沒有子任務依賴兩個父任務執行結果這個場景的配置。
面試官:那有什么方案可以解決分布式場景下的問題嗎?
我:我想到一個簡單的方案,可以在數據庫或緩存中維護一個父任務的狀態標志,比如一張狀態表保存 parentTask1、parentTask2 這兩個任務狀態,每當子任務被觸發時先查一下這兩個狀態是否都被更新成 1,如果是再執行業務邏輯,否則直接退出任務。
面試官:你說的這個方案,如果只跑一次,還可以,如果任務執行比較頻繁,比如兩個父任務每分鐘跑一次,子任務也會每分鐘都會被觸發。你這個方案能滿足要求嗎?
我:一分鐘頻率太高了,需要記錄每次父任務的狀態,而且同一個父任務每分鐘執行的狀態要能區分開。因為可能有極端的情況,parentTask1 上一分鐘的還沒有跑完,但 parentTask2 下一分鐘的已經跑完了,父子任務關聯會出現混亂,如果子任務依賴父任務跑批產生的數據,就會出問題。
面試官:嗯,你說的這個情況是存在的,如果讓你設計,你會怎么解決呢
我:可以給父子任務賦值一個 taskId,根據這個 taskId 來做關聯。比如 parentTask1 的 taskId 是 P202409100000011,parentTask2 配套的 taskId 是 P202409100000012,子任務配套的 taskId 是 P202409100000013。子任務被觸發時,根據 P202409100000013 來判斷 P202409100000011 和 P202409100000012 是否執行完成。子任務下一次觸發時,taskId 就是 P202409100000023,下下次就是 P202409100000033,每次子任務 Id 都是根據父任務 taskId 計算出來。
面試官:這個 taskId 怎么生成和關聯,有思路嗎?
我:這個還是有點難度的。我說一個思路,不一定好。我們定義一張表,如下圖:
圖片
給這個場景定義一個自增 id,這個 id 由 parentTask1 來獲取,獲取后先進行記錄再執行任務。parentTask2 啟動時,找到 parentTask1 有值但是 parentTask2 為空的記錄。先根據 parentTask1 的記錄taskId 計算出自己的 taskId,然后保存數據庫。而子任務被觸發時,從表里查詢已經有 parent_task1_id 和 parent_task2_id 并且兩個狀態都為 1,但是沒有 child_task_id 的記錄,更新 child_task_id 字段,然后執行任務邏輯。
面試官:恭喜你進入下一輪。
本文鏈接:http://www.tebozhan.com/showinfo-26-112704-0.html面試官:一個子任務要依賴兩個父任務完成才能執行,該怎么設計?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com