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
三、CompletableFuture非同步
Future 類透過 get() 方法阻塞等待獲取非同步執行的執行結果,效能比較差。
JDK1。8 中,Java 提供了 CompletableFuture 類,它是基於非同步函數語言程式設計。相對阻塞式等待返回結果,CompletableFuture 可以透過回撥的方式來處理計算結果,實現了非同步非阻塞,效能更優。
CompletableFuture 實現了 Future 和 CompletionStage 介面, 並提供了多種實現非同步程式設計的方法,如supplyAsync, runAsync以及thenApplyAsync。
下面我們使用CompletableFuture來實現上面的例子:
CompletableFuture
我們不需要顯式使用 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
在非同步處理的方法上添加註解
@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依賴:
2。現在我們使用ListenableFuture來實現我們之前的例子:
ExecutorService threadpool = Executors。newCachedThreadPool();ListeningExecutorService service = MoreExecutors。listeningDecorator(threadpool);ListenableFuture
這裡使用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萬字圖文總結,強烈建議收藏!
猜你喜歡
- 2023-01-13帶你走進Linux核心原始碼中最常見的資料結構之「mutex」
- 2021-07-25新現場×曉島,開啟仲夏夜放映季!
- 2021-06-03我的世界:玩MC留下的後遺症,看到街邊的樹,就忍不住想動手!
- 2021-05-11最強大腦:13歲的“程式設計鬼才”和爸爸殺入決賽,排名震驚嘉賓!
- 2021-05-1116核心起步!AMD新一代“撕裂者”處理器即釋出