日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JAVA面試經常會問到:異步操作?什么是異步?與同步有什么區(qū)別?Java異步的是如何實現?有哪些異步實現方式?下面我一一來詳解異步@mikechen

什么是異步?

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

 

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

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

 


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

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

一、線程異步

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

public class AsyncThread extends Thread{
    @Override
    public void run() {
        System.out.println("當前線程名稱:" + this.getName() + ", 執(zhí)行線程名稱:" + Thread.currentThread().getName() + "-hello");
    }
}
public static void main(String[] args) {
 
  // 模擬業(yè)務流程
  // .......
  
    // 創(chuàng)建異步線程 
    AsyncThread asyncThread = new AsyncThread();
 
    // 啟動異步線程
    asyncThread.start();
}

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

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

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

二、Future異步

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

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

@Test
public void futureTest() throws Exception {
 
    System.out.println("main函數開始執(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函數執(zhí)行結束");
 
    System.in.read();
 
}

三、CompletableFuture異步

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

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

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

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

CompletableFuture<Long> 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
@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 ,當對 execute 方法 調用時,通過自定義的線程池 defaultThreadPoolExecutor 異步化執(zhí)行 execute 方法

@Service
public 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 類來執(zhí)行異步操作

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

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

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

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

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

Java異步編程小結

異步編程受到了越來越多的關注,尤其是在 IO 密集型的業(yè)務場景中,相比傳統(tǒng)的同步開發(fā)模式,異步編程的優(yōu)勢越來越明顯,希望以上介紹的5種Java異步編程方式對你有所幫助!

 

分享到:
標簽:Java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰(zhàn)2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定