說(shuō)說(shuō)Java異步調(diào)用的幾種方式
日常開(kāi)發(fā)中,會(huì)經(jīng)常遇到說(shuō),前臺(tái)調(diào)服務(wù),然后觸發(fā)一個(gè)比較耗時(shí)的異步服務(wù),且不用等異步任務(wù)的處理結(jié)果就對(duì)原服務(wù)進(jìn)行返回。這里就涉及的Java異步調(diào)用的一個(gè)知識(shí)。下面本文嘗試將Java異步調(diào)用的多種方式進(jìn)行歸納。
一、通過(guò)創(chuàng)建新線(xiàn)程
首先的我們得認(rèn)識(shí)到,異步調(diào)用的本質(zhì),其實(shí)是通過(guò)開(kāi)啟一個(gè)新的線(xiàn)程來(lái)執(zhí)行。如以下例子:
public static void main(String[] args) throws Exception{ System.out.println("主線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); new Thread(() -> { System.out.println("異步線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("異步線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); }).start(); Thread.sleep(2000); System.out.println("主線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); }
數(shù)據(jù)結(jié)果如下所示,我們知道,System.currentTimeMillis()時(shí)間單位為ms。
主線(xiàn)程 =====> 開(kāi)始 =====> 1627893837146
異步線(xiàn)程 =====> 開(kāi)始 =====> 1627893837200
主線(xiàn)程 =====> 結(jié)束 =====> 1627893839205
異步線(xiàn)程 =====> 結(jié)束 =====> 1627893842212
我們通過(guò)線(xiàn)程休眠來(lái)達(dá)成主線(xiàn)程執(zhí)行時(shí)間2秒左右,異步線(xiàn)程執(zhí)行5秒左右的效果。通過(guò)打印出來(lái)的時(shí)間戳倒數(shù)第四位(秒位)我們可以看出,兩個(gè)的線(xiàn)程執(zhí)行總時(shí)間為5秒左右,符合異步執(zhí)行的特征
以上是采用Runable實(shí)現(xiàn)多線(xiàn)程創(chuàng)建方式的lambda寫(xiě)法,關(guān)于的lambda知識(shí),可參考Java Lambda 表達(dá)式;而關(guān)于多線(xiàn)程的多種實(shí)現(xiàn)方式,Java多線(xiàn)程事務(wù)管理一文有提及,可移步查看
二、通過(guò)線(xiàn)程池
因?yàn)楫惒饺蝿?wù)的實(shí)現(xiàn)本質(zhì)的由新線(xiàn)程來(lái)執(zhí)行任務(wù),所以通過(guò)線(xiàn)程池的也可以實(shí)現(xiàn)異步執(zhí)行。寫(xiě)法同我們利用線(xiàn)程池開(kāi)啟多線(xiàn)程一樣。但由于我們的目的不是執(zhí)行多線(xiàn)程,而是異步執(zhí)行任務(wù),所以一般需要另外一個(gè)線(xiàn)程就夠了。
因此區(qū)別于執(zhí)行多線(xiàn)程任務(wù)的我們常用的newFixedThreadPool,在執(zhí)行異步任務(wù)時(shí),我們用newSingleThreadExecutor 來(lái)創(chuàng)建一個(gè)單個(gè)線(xiàn)程的線(xiàn)程池。
public static void main(String[] args) throws Exception{ System.out.println("主線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(()->{ System.out.println("異步線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("異步線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); }); executorService.shutdown(); // 回收線(xiàn)程池 Thread.sleep(2000); System.out.println("主線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); }
執(zhí)行結(jié)果如下:
主線(xiàn)程 =====> 開(kāi)始 =====> 1627895467578
異步線(xiàn)程 =====> 開(kāi)始 =====> 1627895467635
主線(xiàn)程 =====> 結(jié)束 =====> 1627895469644
異步線(xiàn)程 =====> 結(jié)束 =====> 1627895472649
可以看到,結(jié)果跟第一種結(jié)果是基本一致的。
溫馨提示:不要忘記線(xiàn)程池的回收
三、通過(guò)@Async注解
我們都知道,SpringBoot項(xiàng)目有一個(gè)的很重要的特點(diǎn)就是的注解化。如果你的項(xiàng)目是SpringBoot,那就又多了一種選擇——@Async注解。
使用起來(lái)也非常簡(jiǎn)單,將要異步執(zhí)行的代碼封裝成一個(gè)方法,然后用@Async注解該方法,然后在主方法中直接調(diào)用就行。
@Test public void mainThread() throws Exception{ System.out.println("主線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); collectionBill.asyncThread(); Thread.sleep(2000); System.out.println("主線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); Thread.sleep(4000); // 用于防止jvm停止,導(dǎo)致異步線(xiàn)程中斷 } @Async public void asyncThread(){ System.out.println("異步線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("異步線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); }
執(zhí)行結(jié)果如下:
主線(xiàn)程 =====> 開(kāi)始 =====> 1627897539948
異步線(xiàn)程 =====> 開(kāi)始 =====> 1627897539956
主線(xiàn)程 =====> 結(jié)束 =====> 1627897541965
異步線(xiàn)程 =====> 結(jié)束 =====> 1627897544966
有以下兩點(diǎn)需要注意:
類(lèi)似@Tranctional注解,@Async注解的方法與調(diào)用方法不能在同一個(gè)類(lèi)中,否則不生效
JUnit框架的設(shè)計(jì)不考慮多線(xiàn)程場(chǎng)景,所以主線(xiàn)程退出后,子線(xiàn)程也會(huì)跟著立即退出,所以可以在后面加多線(xiàn)程休眠時(shí)間來(lái)觀察異步線(xiàn)程的執(zhí)行情況
四、通過(guò)CompletableFuture
CompletableFuture是JDK1.8的新特性,是對(duì)Future的擴(kuò)展。CompletableFuture實(shí)現(xiàn)了CompletionStage接口和Future接口,增加了異步回調(diào)、流式處理、多個(gè)Future組合處理的能力。
實(shí)現(xiàn)代碼如下:
public static void main(String[] args) throws Exception{ System.out.println("主線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); ExecutorService executorService = Executors.newSingleThreadExecutor(); CompletableFuture.runAsync(() ->{ System.out.println("異步線(xiàn)程 =====> 開(kāi)始 =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("異步線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); },executorService); executorService.shutdown(); // 回收線(xiàn)程池 Thread.sleep(2000); System.out.println("主線(xiàn)程 =====> 結(jié)束 =====> " + System.currentTimeMillis()); }
同樣可以實(shí)現(xiàn)類(lèi)似的結(jié)果如下:
主線(xiàn)程 =====> 開(kāi)始 =====> 1627898354914
異步線(xiàn)程 =====> 開(kāi)始 =====> 1627898354977
主線(xiàn)程 =====> 結(jié)束 =====> 1627898356980
異步線(xiàn)程 =====> 結(jié)束 =====> 1627898359979
CompletableFuture有者非常強(qiáng)大的功能,能給我們帶來(lái)非常絲滑的編程體驗(yàn)。后續(xù)會(huì)寫(xiě)一篇文章來(lái)詳細(xì)介紹CompletableFuture
到此這篇關(guān)于說(shuō)說(shuō)Java異步調(diào)用的幾種方式的文章就介紹到這了,更多相關(guān)Java異步調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot響應(yīng)處理之以Json數(shù)據(jù)返回的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot整合Web開(kāi)發(fā)其中Json數(shù)據(jù)返回的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之寵物醫(yī)院與商城一體的系統(tǒng)的實(shí)現(xiàn)
這是一個(gè)使用了java+Springboot+Jsp+maven+Mysql開(kāi)發(fā)的寵物醫(yī)院與商城一體的系統(tǒng),是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有寵物醫(yī)院和寵物商城該有的所有功能,感興趣的朋友快來(lái)看看吧2022-02-02springboot項(xiàng)目Redis統(tǒng)計(jì)在線(xiàn)用戶(hù)的實(shí)現(xiàn)示例
最近做個(gè)項(xiàng)目需要統(tǒng)計(jì)在線(xiàn)用戶(hù),本文主要介紹了springboot項(xiàng)目Redis統(tǒng)計(jì)在線(xiàn)用戶(hù)的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06Java的long和bigint長(zhǎng)度對(duì)比詳解
在本文中小編給大家分享了關(guān)于Java的long和bigint長(zhǎng)度比較的知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們學(xué)習(xí)參考下。2019-07-07