哦哇資訊網

Java非同步程式設計(5種非同步實現方式詳解)

由 mikechen的網際網路架構 發表于 美食2022-12-10

Java面試經常會問到:非同步操作?什麼是非同步?與同步有什麼區別?Java非同步的是如何實現?有哪些非同步實現方式?下面我一一來詳解非同步

@mikechen

什麼是非同步?

首先我們先來看看一個同步的使用者註冊例子,流程如下:

在同步操作中,我們執行到

插入資料庫

的時候,我們必須等待這個方法徹底執行完才能執行“

傳送簡訊

”這個操作,如果

插入資料庫

這個動作執行時間較長,傳送簡訊需要等待,這就是典型的同步場景。

於是聰明的人們開始思考,如果兩者關聯性不強,能不能將一些非核心業務從主流程中剝離出來,於是有了非同步程式設計雛形,改進後的流程如下:

這就是非同步程式設計,它是程式併發執行的一種手段,它允許多個事件同時發生,當程式呼叫需要長時間執行的方法時,它不會阻塞當前的執行流程,程式可以繼續執行。

在聊完非同步程式設計後,那麼我們一起來看看Java裡面實現非同步程式設計究竟有哪些方式呢?

一、執行緒非同步

在 Java 語言中最簡單使用非同步程式設計的方式就是建立一個 執行緒來實現,如果你使用的 JDK 版本是 8 以上的話,可以使用 Lambda 表示式 會更加簡潔。

public class AsyncThread extends Thread{ @Override public void run() { System。out。println(“當前執行緒名稱:” + this。getName() + “, 執行執行緒名稱:” + Thread。currentThread()。getName() + “-hello”); }}

public static void main(String[] args) { // 模擬業務流程 // ……。 // 建立非同步執行緒 AsyncThread asyncThread = new AsyncThread(); // 啟動非同步執行緒 asyncThread。start();}

當然如果每次都建立一個 Thread執行緒,頻繁的建立、銷燬,浪費系統資源,我們可以採用執行緒池:

private ExecutorService executor = Executors。newCachedThreadPool() ; public void fun() throws Exception { executor。submit(new Runnable(){ @override public void run() { try { //要執行的業務程式碼,我們這裡沒有寫方法,可以讓執行緒休息幾秒進行測試 Thread。sleep(10000); System。out。print(“睡夠啦~”); }catch(Exception e) { throw new RuntimeException(“報錯啦!!”); } } }); }

將業務邏輯封裝到 Runnable 或 Callable 中,交由 執行緒池 來執行。

二、Future非同步

上述方式雖然達到了多執行緒並行處理,但有些業務不僅僅要執行過程,還要獲取執行結果,後續提供在JUC包增加了Future。

從字面意思理解就是未來的意思,但使用起來卻著實有點雞肋,並不能實現真正意義上的非同步,獲取結果時需要阻塞執行緒,或者不斷輪詢。

@Testpublic void futureTest() throws Exception { System。out。println(“main函式開始執行”); ExecutorService executor = Executors。newFixedThreadPool(1); Future future = executor。submit(new Callable() { @Override public Integer call() throws Exception { System。out。println(“===task start===”); Thread。sleep(5000); System。out。println(“===task finish===”); return 3; } }); //這裡需要返回值時會阻塞主執行緒,如果不需要返回值使用是OK的。倒也還能接收 //Integer result=future。get(); System。out。println(“main函式執行結束”); System。in。read(); }

三、CompletableFuture非同步

Future 類透過 get() 方法阻塞等待獲取非同步執行的執行結果,效能比較差。

JDK1。8 中,Java 提供了 CompletableFuture 類,它是基於非同步函數語言程式設計。相對阻塞式等待返回結果,CompletableFuture 可以透過回撥的方式來處理計算結果,實現了非同步非阻塞,效能更優。

CompletableFuture 實現了 Future 和 CompletionStage 介面, 並提供了多種實現非同步程式設計的方法,如supplyAsync, runAsync以及thenApplyAsync。

下面我們使用CompletableFuture來實現上面的例子:

CompletableFuture completableFuture = CompletableFuture。supplyAsync(() -> factorial(number));while (!completableFuture。isDone()) { System。out。println(“CompletableFuture is not finished yet。。。”);}long result = completableFuture。get();

我們不需要顯式使用 ExecutorService,CompletableFuture 內部使用了 ForkJoinPool 來處理非同步任務,這使得我們的程式碼變的更簡潔。

四、SpringBoot @Async非同步

在@Async註解之前,使用多執行緒需要使用JDK的原生方法,非常麻煩,當有了@Async之後就比較簡單了。

首先,使用 @EnableAsync 啟用非同步註解:

@SpringBootApplication@EnableAsyncpublic class StartApplication { public static void main(String[] args) { SpringApplication。run(StartApplication。class, args); }}

自定義執行緒池:

@Configuration@Slf4jpublic class ThreadPoolConfiguration { @Bean(name = “defaultThreadPoolExecutor”, destroyMethod = “shutdown”) public ThreadPoolExecutor systemCheckPoolExecutorService() { return new ThreadPoolExecutor(3, 10, 60, TimeUnit。SECONDS, new LinkedBlockingQueue(10000), new ThreadFactoryBuilder()。setNameFormat(“default-executor-%d”)。build(), (r, executor) -> log。error(“system pool is full! ”)); }}

在非同步處理的方法上添加註解

@Async

,當對

execute 方法

呼叫時,透過自定義的執行緒池

defaultThreadPoolExecutor

非同步化執行

execute 方法

@Servicepublic class AsyncServiceImpl implements AsyncService { @Async(“defaultThreadPoolExecutor”) public Boolean execute(Integer num) { System。out。println(“執行緒:” + Thread。currentThread()。getName() + “ , 任務:” + num); return true; }}

用 @Async 註解標記的方法,稱為非同步方法。在spring boot應用中使用 @Async 很簡單:

呼叫非同步方法類上或者啟動類加上註解 @EnableAsync

在需要被非同步呼叫的方法外加上 @Async

所使用的 @Async 註解方法的類物件應該是Spring容器管理的bean物件;

五、Guava非同步

Guava 提供了 ListenableFuture 類來執行非同步操作

1.首先我們需要新增 guava 的maven依賴:

com。google。guava guava 28。2-jre

2。現在我們使用ListenableFuture來實現我們之前的例子:

ExecutorService threadpool = Executors。newCachedThreadPool();ListeningExecutorService service = MoreExecutors。listeningDecorator(threadpool);ListenableFuture guavaFuture = (ListenableFuture) service。submit(()-> factorial(number));long result = guavaFuture。get();

這裡使用MoreExecutors獲取ListeningExecutorService類的例項,然後ListeningExecutorService。submit執行非同步任務,並返回 ListenableFuture例項。

Java非同步程式設計小結

非同步程式設計受到了越來越多的關注,尤其是在 IO 密集型的業務場景中,相比傳統的同步開發模式,非同步程式設計的優勢越來越明顯,希望以上介紹的5種Java非同步程式設計方式對你有所幫助!

以上!

合集●架構技術乾貨

1。分散式架構設計從0到1全部合集,強烈建議收藏!

2。Java多線與併發程式設計從0到1全部合集,強烈建議收藏!

3。JVM虛擬機器系從0到1全部合集,強烈建議收藏!

4。Spring系列從0到1全部合集,強烈建議收藏!

5。Java設計模式:23種設計模式(萬字圖文全面總結)

6。史上最強訊息佇列MQ萬字圖文總結,強烈建議收藏!

TAG: 非同步執行緒程式設計Javapublic