欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中5種異步實(shí)現(xiàn)的方式詳解

 更新時間:2022年09月19日 10:17:35   作者:mikechen的互聯(lián)網(wǎng)架構(gòu)  
同步操作如果遇到一個耗時的方法,需要阻塞等待,那么我們有沒有辦法解決呢?讓它異步執(zhí)行,下面我會詳解異步及實(shí)現(xiàn),需要的可以參考一下

一、什么是異步

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

在同步操作中,我們執(zhí)行到插入數(shù)據(jù)庫的時候,我們必須等待這個方法徹底執(zhí)行完才能執(zhí)行“發(fā)送短信”這個操作,如果插入數(shù)據(jù)庫這個動作執(zhí)行時間較長,發(fā)送短信需要等待,這就是典型的同步場景。

于是聰明的人們開始思考,如果兩者關(guān)聯(lián)性不強(qiáng),能不能將一些非核心業(yè)務(wù)從主流程中剝離出來,于是有了異步編程雛形,改進(jìn)后的流程如下:

這就是異步編程,它是程序并發(fā)運(yùn)行的一種手段,它允許多個事件同時發(fā)生,當(dāng)程序調(diào)用需要長時間運(yùn)行的方法時,它不會阻塞當(dāng)前的執(zhí)行流程,程序可以繼續(xù)運(yùn)行。

在聊完異步編程后,那么我們一起來看看Java里面實(shí)現(xiàn)異步編程究竟有哪些方式呢?

二、線程異步

在 Java 語言中最簡單使用異步編程的方式就是創(chuàng)建一個 線程來實(shí)現(xiàn),如果你使用的 JDK 版本是 8 以上的話,可以使用 Lambda 表達(dá)式 會更加簡潔。

public class AsyncThread extends Thread{
    @Override
    public void run() {
        System.out.println("當(dāng)前線程名稱:" + this.getName() + ", 執(zhí)行線程名稱:" + Thread.currentThread().getName() + "-hello");
    }
}
public static void main(String[] args) {

  // 模擬業(yè)務(wù)流程
  // .......
  
    // 創(chuàng)建異步線程 
    AsyncThread asyncThread = new AsyncThread();

    // 啟動異步線程
    asyncThread.start();
}

當(dāng)然如果每次都創(chuàng)建一個 Thread線程,頻繁的創(chuàng)建、銷毀,浪費(fèi)系統(tǒng)資源,我們可以采用線程池:

private ExecutorService executor = Executors.newCachedThreadPool() ;
 
    public void fun() throws Exception {
 
        executor.submit(new Runnable(){
 
            @override
 
                public void run() {
 
                    try {
                     //要執(zhí)行的業(yè)務(wù)代碼,我們這里沒有寫方法,可以讓線程休息幾秒進(jìn)行測試
 
                        Thread.sleep(10000);
 
                        System.out.print("睡夠啦~");
 
                    }catch(Exception e) {
 
                        throw new RuntimeException("報錯啦??!");
 
                    }
 
                }
 
        });
 
    }

將業(yè)務(wù)邏輯封裝到 Runnable 或 Callable 中,交由 線程池 來執(zhí)行。

三、Future異步

上述方式雖然達(dá)到了多線程并行處理,但有些業(yè)務(wù)不僅僅要執(zhí)行過程,還要獲取執(zhí)行結(jié)果,后續(xù)提供在JUC包增加了Future。

從字面意思理解就是未來的意思,但使用起來卻著實(shí)有點(diǎn)雞肋,并不能實(shí)現(xiàn)真正意義上的異步,獲取結(jié)果時需要阻塞線程,或者不斷輪詢。

@Test
public void futureTest() throws Exception {

    System.out.println("main函數(shù)開始執(zhí)行");

    ExecutorService executor = Executors.newFixedThreadPool(1);
    Future<Integer> future = executor.submit(new Callable<Integer>() {
        @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函數(shù)執(zhí)行結(jié)束");

    System.in.read();

}

四、CompletableFuture異步

Future 類通過 get() 方法阻塞等待獲取異步執(zhí)行的運(yùn)行結(jié)果,性能比較差。

JDK1.8 中,Java 提供了 CompletableFuture 類,它是基于異步函數(shù)式編程。相對阻塞式等待返回結(jié)果,CompletableFuture 可以通過回調(diào)的方式來處理計算結(jié)果,實(shí)現(xiàn)了異步非阻塞,性能更優(yōu)。

CompletableFuture 實(shí)現(xiàn)了 Future 和 CompletionStage 接口, 并提供了多種實(shí)現(xiàn)異步編程的方法,如supplyAsync, runAsync以及thenApplyAsync。

下面我們使用CompletableFuture來實(shí)現(xiàn)上面的例子:

CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> factorial(number));
while (!completableFuture.isDone()) {
    System.out.println("CompletableFuture is not finished yet...");
}
long result = completableFuture.get();

我們不需要顯式使用 ExecutorService,CompletableFuture 內(nèi)部使用了 ForkJoinPool 來處理異步任務(wù),這使得我們的代碼變的更簡潔。

五、SpringBoot @Async異步

在@Async注解之前,使用多線程需要使用JDK的原生方法,非常麻煩,當(dāng)有了@Async之后就比較簡單了。

首先,使用 @EnableAsync 啟用異步注解:

@SpringBootApplication
@EnableAsync
public class StartApplication {

    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}

自定義線程池:

@Configuration
@Slf4j
public class ThreadPoolConfiguration {

    @Bean(name = "defaultThreadPoolExecutor", destroyMethod = "shutdown")
    public ThreadPoolExecutor systemCheckPoolExecutorService() {

        return new ThreadPoolExecutor(3, 10, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(10000),
                new ThreadFactoryBuilder().setNameFormat("default-executor-%d").build(),
                (r, executor) -> log.error("system pool is full! "));
    }
}

在異步處理的方法上添加注解 @Async ,當(dāng)對 execute 方法 調(diào)用時,通過自定義的線程池 defaultThreadPoolExecutor 異步化執(zhí)行  execute 方法

@Service
public class AsyncServiceImpl implements AsyncService {

    @Async("defaultThreadPoolExecutor")
    public Boolean execute(Integer num) {
        System.out.println("線程:" + Thread.currentThread().getName() + " , 任務(wù):" + num);
        return true;
    }

}

用 @Async 注解標(biāo)記的方法,稱為異步方法。在spring boot應(yīng)用中使用 @Async 很簡單:

  • 調(diào)用異步方法類上或者啟動類加上注解 @EnableAsync
  • 在需要被異步調(diào)用的方法外加上 @Async
  • 所使用的 @Async 注解方法的類對象應(yīng)該是Spring容器管理的bean對象;

六、Guava異步

Guava 提供了 ListenableFuture 類來執(zhí)行異步操作

1.首先我們需要添加 guava 的maven依賴:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
</dependency>

2.現(xiàn)在我們使用ListenableFuture來實(shí)現(xiàn)我們之前的例子:

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

這里使用MoreExecutors獲取ListeningExecutorService類的實(shí)例,然后ListeningExecutorService.submit執(zhí)行異步任務(wù),并返回 ListenableFuture實(shí)例。

到此這篇關(guān)于Java中5種異步實(shí)現(xiàn)的方式詳解的文章就介紹到這了,更多相關(guān)Java異步實(shí)現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java使用IntelliJ IDEA連接MySQL的詳細(xì)教程

    Java使用IntelliJ IDEA連接MySQL的詳細(xì)教程

    這篇文章主要給大家介紹了關(guān)于Java使用IntelliJ IDEA連接MySQL的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java幸運(yùn)28系統(tǒng)搭建數(shù)組的使用實(shí)例詳解

    Java幸運(yùn)28系統(tǒng)搭建數(shù)組的使用實(shí)例詳解

    在本篇文章里小編給大家整理了關(guān)于Java幸運(yùn)28系統(tǒng)搭建數(shù)組的使用實(shí)例內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。
    2019-09-09
  • 詳解Http請求中Content-Type講解以及在Spring MVC中的應(yīng)用

    詳解Http請求中Content-Type講解以及在Spring MVC中的應(yīng)用

    這篇文章主要介紹了Http請求中Content-Type講解以及在Spring MVC中的應(yīng)用的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 探究實(shí)現(xiàn)Aware接口的原理及使用

    探究實(shí)現(xiàn)Aware接口的原理及使用

    這篇文章主要為大家介紹了探究實(shí)現(xiàn)Aware接口的原理及使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 關(guān)于SpringBoot使用Redis空指針的問題(不能成功注入的問題)

    關(guān)于SpringBoot使用Redis空指針的問題(不能成功注入的問題)

    這篇文章主要介紹了關(guān)于SpringBoot使用Redis空指針的問題(不能成功注入的問題),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • @RequestBody,@RequestParam和@Param的區(qū)別說明

    @RequestBody,@RequestParam和@Param的區(qū)別說明

    這篇文章主要介紹了@RequestBody,@RequestParam和@Param的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 詳解Spring boot Admin 使用eureka監(jiān)控服務(wù)

    詳解Spring boot Admin 使用eureka監(jiān)控服務(wù)

    本篇文章主要介紹了詳解Spring boot Admin 使用eureka監(jiān)控服務(wù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • VsCode配置java環(huán)境的詳細(xì)圖文教程

    VsCode配置java環(huán)境的詳細(xì)圖文教程

    vscode是一個免費(fèi)的代碼編輯器,支持多種主題,應(yīng)用起來簡單方便,下面這篇文章主要給大家介紹了關(guān)于VsCode配置java環(huán)境的詳細(xì)圖文教程,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • Java實(shí)現(xiàn)雙端鏈表LinkedList

    Java實(shí)現(xiàn)雙端鏈表LinkedList

    本文主要介紹了Java實(shí)現(xiàn)雙端鏈表LinkedList,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Spring?Cloud?Stream消息驅(qū)動組件使用方法介紹

    Spring?Cloud?Stream消息驅(qū)動組件使用方法介紹

    Spring?Cloud?Stream?消息驅(qū)動組件幫助我們更快速,更方便,更友好的去構(gòu)建消息驅(qū)動微服務(wù)的。當(dāng)時定時任務(wù)和消息驅(qū)動的?個對比。消息驅(qū)動:基于消息機(jī)制做一些事情
    2022-09-09

最新評論