spring boot @Async 的異步調用,涉及CountDownLatch堵塞和Future<T>的超時處理

最近項目的一個業務場景需要使用異步 , 碼代碼到斷斷續續完善代碼 . 查詢了挺多的資料文檔, 現在記錄一下.

一 : 業務場景 

        類似QQ 中的設置頁面 , 左側每個選項對應右側的具體設置 , 項目中暫且簡化爲需要插入7條數據到不同數據表, 第一條數據和最後一條數據是爲了提醒用戶開始和結束 。 其中主方法是插入1 ,立刻給用戶返回數據(2-6的數據插入費時間,如果都等到插入成功再去返回給用戶體驗不好), 這時候我們需要開線程去分別執行2-6的插入工作,同時,7的插入必須是在2-6插入之後纔可以運行.(2-6是隨機的,可能全插入,可能全部不插) 。 做的結果是 : 第一條數據插入數據表,然後就直接返回用戶,執行成功,中間2-6的執行過程異步執行,然後第7條數據在異步結束之後插入

二 : 參數 

        創建一個是一個實體類來存儲2-6的所有字段,添加一個標識字段來區分。存入List中 , LIst<T> 

三 : 使用技術點

        ① : spring boot 集成的異步,使用@Async來開啓異步,模塊啓動類添加@EnableAsync 註解

                  實質上是開啓線程執行異步的類,互不干擾執行。

        ② : CountDownLatch的使用

                 上面說到,我需要異步執行2-6,返回結果之後纔可以去執行7。 所以此時,我們使用到了CountDownLatch工具類來完成線程之間的堵塞。CountDownLatch是一種java.util.concurrent包下一個同步工具類,它允許一個或多個線程等待直到在其他線程中一組操作執行完成。

                 1、CountDownLatch latch =new CountDownLatch(count); //構造對象時候 需要傳入參數count

            2、latch .await()  能夠阻塞線程 直到調用count次latch .countDown() 方法才釋放線程

            3、end.countDown() 可以在多個線程中調用  計算調用次數是所有線程調用次數的總和

                  具體代碼如下 :

        ③ :異步超時處理 

                因爲異步是在後臺執行,該項目的異步執行還需要調用其他模塊的接口(參考 :spring cloud eureka的使用),導致執行速度慢,考慮到異步可能會無限執行下去,消耗資源,我們添加異步超時的處理。

                這裏使用了Future<T> 接口。    

                boolean cancel(boolean mayInterruptIfRunning); 取消正在執行的異步,取消成功返回true,取消失敗返回false。參數填true既取消異步,填false既不取消異步。

                boolean isCancelled(); 任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。

                boolean isDone(); 表示任務是否已經完成,完成返回true ,反之false。

                V get()throws InterruptedException, ExecutionException; 獲取異步線程的執行結果,這個方法是存在堵塞效果的,任務執行完成之後就會返回執行結果,true或false返回的數據類型預Future<T> 的T一致

                Vget(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;  設置超時時間,設置時間內異步完成則則成功,超時則返回失敗,返回的數據類型預Future<T> 的T一致

                參考上圖,我們使用到了取消和設置超時時間的方法    

                注意 : 在寫代碼的過程中,我們一開始是直接在controller上面開啓異步,2-6直接在異步類中開啓超時,這時候不生效。查看原因是我們在異步類中的總方法調用另外五個異步,他們實際上還是一個線程。此時我們在service中調用,主方法的異步在service層,剩下五個小的異步在異步類,此時是6個線程,調用成功。

        ④ : 異步的事務

                在Async 方法上標註@Transactional是沒用的。 

                在Async 方法調用的Service上標註@Transactional 有效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章