java常用異步說明

簡介

異步編程是一種編程範式,允許在等待某些操作(如IO操作)完成的過程中,暫停當前線程的執行,讓出控制權,從而允許其他操作或線程併發執行。在Java中,有多種實現異步編程的方式,包括使用FutureCallable接口、CompletableFuture類以及ExecutorService等。

下面是一個簡單的Java異步編程示例,使用了FutureCallable接口:

import java.util.concurrent.*;
public class AsyncDemo {
    public static void main(String[] args{
        // 創建一個線程池
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 提交一個異步任務
        Future<Integer> future = executor.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception 
{
                // 模擬耗時操作
                Thread.sleep(1000);
                return 42;
            }
        });

        // 在等待結果的過程中,主線程可以繼續執行其他任務
        System.out.println("Doing other work...");

        try {
            // 獲取異步任務的結果
            Integer result = future.get();
            System.out.println("Result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            // 關閉線程池
            executor.shutdown();
        }
    }
}

常用異步編程方式

1.注入 ThreadPoolTaskExecutor

@AutowiredSpring 框架中的一個註解,用於自動注入依賴。在這個例子中,ThreadPoolTaskExecutor 是一個線程池任務執行器,用於執行異步任務。

優點:

  • 提高系統性能:通過使用線程池,可以有效地利用系統資源,避免頻繁地創建和銷燬線程,從而提高系統性能。
  • 易於管理:線程池提供了對線程的集中管理,可以方便地調整線程池的大小、優先級等參數。
  • 提供任務調度功能:線程池可以根據任務的優先級、延遲時間等參數進行任務調度,確保高優先級的任務優先執行。

缺點:

  • 資源消耗:線程池會佔用一定的系統資源,如內存、CPU 等,如果配置不當,可能會導致資源浪費。
  • 可能導致死鎖:在多線程環境下,如果沒有正確地使用同步機制,可能會導致死鎖等問題。

場景使用:

  • 異步處理:當需要執行耗時操作時,可以使用線程池將任務放入隊列中,由線程池中的線程異步執行,提高系統的響應速度。
  • 定時任務:線程池可以用於執行定時任務,如定時清理緩存、定時發送郵件等。
    無返回demo:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

@Component
public class TaskExecutorDemo {

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    public void executeTask() {
        taskExecutor.execute(() -> {
            // 這裏是需要執行的任務代碼
            System.out.println("任務執行中...");
        });
    }
}

有返回demo

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;

@Component
public class TaskExecutorDemo {

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    public Future<String> executeTask() {
        return taskExecutor.submit(() -> {
            // 這裏是需要執行的任務代碼
            System.out.println("任務執行中...");
            return "任務執行結果";
        });
    }
}

future.get() 方法會阻塞當前線程,直到任務執行完成。如果任務執行過程中發生異常,future.get() 方法會拋出 ExecutionException 異常。因此,在使用 future.get()方法時,需要進行異常處理。

2.Executors.newCachedThreadPool()

ExecutorService service = Executors.newCachedThreadPool(); 這行代碼創建了一個緩存線程池,它可以根據實際情況自動調整線程數量。

優點:

  • 靈活性:緩存線程池可以根據任務的數量動態地創建和銷燬線程,避免了固定線程數量的浪費和資源佔用。
  • 性能優化:當任務數量增加時,緩存線程池會自動增加線程數量來提高執行效率;當任務數量減少時,緩存線程池會自動減少線程數量以節省資源。

缺點:

  • 資源消耗:由於緩存線程池會根據任務數量動態調整線程數量,可能會導致系統資源的過度使用和浪費。
  • 線程管理複雜:緩存線程池需要對線程進行動態管理,增加了系統的複雜度和維護成本。

場景使用:

  • 大量短週期任務:當有大量短週期任務需要執行時,可以使用緩存線程池來提高執行效率。
  • 不確定任務數量:當任務數量不確定或者經常變化時,緩存線程池可以根據實際情況自動調整線程數量,提高系統的穩定性和性能。
    代碼demo
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new Runnable() {
            @Override
            public void run() {
                // 這裏是需要執行的任務代碼
                System.out.println("任務執行中...");
            }
        });
    }
}

3. CompletableFuture

CompletableFutureJava 8 引入的一個異步編程工具類,它可以幫助我們以非阻塞的方式執行任務,提高程序的執行效率。下面是 CompletableFuture 的優缺點、使用場景以及具體代碼示例:

優點:

  • 異步執行:CompletableFuture 可以異步地執行任務,不會阻塞主線程,提高了程序的執行效率。
  • 鏈式調用:CompletableFuture 支持鏈式調用,可以將多個異步任務串聯起來,形成任務流水線,提高了代碼的可讀性和可維護性。
  • 異常處理:CompletableFuture 提供了豐富的異常處理方法,可以方便地處理異步任務中的異常情況。
  • 組合操作:CompletableFuture 支持多種組合操作,如 thenApplythenAcceptthenCompose 等,可以方便地對異步任務的結果進行處理。

缺點:

  • 學習成本:CompletableFuture 的使用相對複雜,需要一定的學習成本。
  • 錯誤處理:CompletableFuture 的錯誤處理方式較爲繁瑣,需要手動處理異常或者使用 try-catch語句。

使用場景:

  • 異步IO操作:在需要進行網絡請求、文件讀寫等耗時操作時,可以使用CompletableFuture進行異步處理,提高程序的執行效率。
  • 併發編程:在多線程環境下,可以使用CompletableFuture進行任務的並行處理,提高程序的執行效率。
  • 異步計算:在需要進行大量計算的場景下,可以使用CompletableFuture進行異步計算,提高程序的執行效率。

代碼demo

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        // 創建一個異步任務
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello, CompletableFuture!";
        });

        // 對異步任務的結果進行處理
        future.thenAccept(result -> System.out.println("Result: " + result));

        // 等待異步任務完成
        future.join();
    }
}

4. ThreadPoolExecutor

ThreadPoolExecutorJava 併發編程中的一個重要組件,它可以用來創建和管理線程池。下面是 ThreadPoolExecutor 的優缺點、使用場景以及具體代碼示例:

優點:

  • 資源重用:ThreadPoolExecutor 可以複用已創建的線程,減少了線程創建和銷燬的開銷。
  • 管理線程:ThreadPoolExecutor 提供了豐富的線程管理功能,如線程池大小、任務隊列等,方便了線程的管理和維護。
  • 提高性能:通過合理地配置線程池參數,可以提高程序的性能。
  • 異常處理:ThreadPoolExecutor 提供了異常處理機制,可以方便地處理線程執行過程中的異常情況。

缺點:

  • 學習成本:ThreadPoolExecutor 的使用相對複雜,需要一定的學習成本。
  • 錯誤處理:ThreadPoolExecutor 的錯誤處理方式較爲繁瑣,需要手動處理異常或者使用 try-catch 語句。

使用場景:

  • 高併發場景:在需要進行大量併發操作的場景下,可以使用ThreadPoolExecutor來提高程序的執行效率。
    I- O密集型任務:在需要進行大量 IO 操作的場景下,可以使用ThreadPoolExecutor來提高程序的執行效率。
  • 定時任務:在需要進行定時任務的場景下,可以使用ThreadPoolExecutor來實現任務的定時執行。

demo

import java.util.concurrent.*;

public class ThreadPoolExecutorDemo {
    public static void main(String[] args) {
        // 創建一個固定大小的線程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(51060, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

        // 提交任務到線程池
        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                System.out.println("Task executed by thread: " + Thread.currentThread().getName());
            });
        }

        // 關閉線程池
        executor.shutdown();
    }
}

有返回值

import java.util.concurrent.*;

public class ThreadPoolExecutorDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 創建一個固定大小的線程池
        private ThreadPoolExecutor threadPoolServiceGuideOpenIdByBuyerFxy = new ThreadPoolExecutor(
            82010, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1000),
            new ThreadFactoryBuilder().setNameFormat("xxx-check-pool-%d").build(),
            new ThreadPoolExecutor.DiscardOldestPolicy());

        // 提交任務到線程池並獲取 Future 對象
        Future<Integer> future = executor.submit(() -> {
            int sum = 0;
            for (int i = 1; i <= 100; i++) {
                sum += i;
            }
            return sum;
        });

        // 獲取任務執行結果
        int result = future.get();
        System.out.println("Task result: " + result);

        // 關閉線程池
        executor.shutdown();
    }
}

這段代碼創建了一個名爲threadPoolServiceGuideOpenIdByBuyerFxy的線程池對象。該線程池具有以下配置:

核心線程數(corePoolSize):8個線程
最大線程數(maximumPoolSize):20個線程
空閒線程存活時間(keepAliveTime):10
時間單位(timeUnit):秒
任務隊列(workQueue):一個容量爲1000的ArrayBlockingQueue
線程工廠(threadFactory):使用ThreadFactoryBuilder設置線程名稱格式爲"fxy-item-check-pool-%d"
拒絕策略(rejectedExecutionHandler):DiscardOldestPolicy,即丟棄最舊的任務
這個線程池可以用於執行一些需要併發處理的任務,例如檢查購買者信息、處理商品等操作。

5. @Async註解

Spring@Async註解是用於實現異步方法調用的。它可以將一個方法標記爲異步執行,使得該方法在單獨的線程中運行,而不會阻塞主線程。

優點:

  • 提高程序的性能和響應速度:通過將耗時的操作放在單獨的線程中執行,可以避免主線程被阻塞,從而提高程序的吞吐量和響應速度。
  • 簡化代碼:使用@Async註解可以簡化異步方法的編寫,無需手動創建線程或使用線程池。
  • 易於管理:Spring框架提供了對異步方法的管理和監控,可以方便地跟蹤異步任務的狀態和結果。

缺點:

  • 複雜性增加:使用@Async註解會增加代碼的複雜性,需要處理異步任務的生命週期和異常情況。
  • 線程安全問題:異步方法可能會涉及到共享資源的訪問,需要注意線程安全問題,避免出現競態條件和數據不一致的情況。

場景使用:

  • 高併發場景:對於需要處理大量請求和大量數據的應用程序,可以使用@Async註解來提高系統的併發能力和響應速度。
  • 耗時操作:對於一些耗時較長的操作,如數據庫查詢、文件讀寫等,可以使用@Async註解將其異步執行,避免阻塞主線程。

具體代碼demo:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class AsyncDemo {

    @Async
    public void asyncMethod() {
        // 異步執行的代碼邏輯
        System.out.println("異步方法執行中...");
    }
}

@Async線程池

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("Async-");
        executor.initialize();
        return executor;
    }
}
上述配置創建了一個名爲"asyncExecutor"的線程池,其中pool-size設置爲10,表示線程池中的線程數量爲10。你可以根據實際需求調整pool-size的值。

接下來,你可以在需要異步執行的方法上添加@Async註解,並指定使用的線程池名稱:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class AsyncDemo {

    @Async("asyncExecutor")
    public void asyncMethod() {
        // 異步執行的代碼邏輯
        System.out.println("異步方法執行中...");
    }
}

6. ScheduledExecutorService

ScheduledExecutorServiceJava中用於執行定時任務的接口,它是ExecutorService的一個子接口。它提供了一種方便的方式來調度和執行延遲或週期性的任務。

優點:

  • 靈活性:ScheduledExecutorService允許你以不同的時間單位來指定任務的延遲或週期執行。
  • 可配置性:你可以控制線程池的大小、任務的優先級等參數,以滿足特定的需求。
  • 易於使用:它提供了簡單的方法來提交和取消任務,以及獲取任務的狀態和結果。

缺點:

  • 資源消耗:如果創建過多的線程或者任務數量過多,可能會導致系統資源的浪費和性能下降。
  • 異常處理:在任務執行過程中可能會拋出異常,需要適當處理這些異常以避免程序崩潰。

場景使用:

  • 定時任務:適用於需要按照固定的時間間隔或者特定時間點執行的任務,例如定時清理緩存、定時發送郵件等。
  • 週期性任務:適用於需要週期性執行的任務,例如定期檢查系統狀態、定期備份數據等。

具體代碼demo:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorServiceDemo {
    public static void main(String[] args) {
        // 創建一個ScheduledExecutorService實例
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);

        // 定義一個Runnable任務
        Runnable task = () -> {
            System.out.println("Task executed at " + new Date());
        };

        // 提交任務並設置延遲執行時間
        scheduledExecutorService.schedule(task, 5, TimeUnit.SECONDS);

        // 關閉ScheduledExecutorService
        scheduledExecutorService.shutdown();
    }
}

Java異步操作的優缺點

Java異步操作的優點具體如下:

  • 提高併發性:異步操作允許多個任務並行執行,這樣可以更好地利用系統資源,尤其是在多核處理器上。
  • 提升響應性:在處理耗時的IO操作時,異步操作可以避免阻塞主線程,從而提高應用程序的響應速度。

Java異步操作的缺點具體如下:

  • 編程複雜性:異步編程通常需要處理回調函數、狀態同步等複雜的邏輯,這可能會增加代碼的複雜性和出錯的風險。
  • 線程安全:在多線程環境下,需要確保數據的一致性和線程安全,這可能需要使用額外的同步機制。
  • 性能開銷:雖然異步操作可以提高併發性,但是過多的線程可能會導致上下文切換和同步的開銷,從而影響性能。

使用異步考慮

  • 任務的性質:對於IO密集型或需要等待外部資源的任務,如網絡請求、文件讀寫等,使用異步可以顯著提高效率。然而,對於計算密集型任務,由於Java的線程模型,過多的線程可能導致上下文切換,反而降低性能。

  • 系統資源:異步操作通常意味着更多的線程或任務在後臺運行。這可能會導致系統資源的消耗增加,如內存和CPU。因此,需要根據系統的資源情況來合理地管理異步任務的數量。

  • 錯誤處理:在異步操作中,錯誤處理變得更加複雜。因爲操作是異步的,所以異常可能不會立即顯現。需要確保有合適的機制來捕獲和處理這些異常。

  • 代碼複雜性:異步編程可能會使代碼邏輯更加複雜,特別是當涉及到回調函數嵌套時。這可能導致代碼難以理解和維護。

  • 線程安全:在多線程環境下,需要特別注意數據一致性和線程安全問題。可能需要使用同步機制來保護共享數據。

  • 調試難度:由於異步操作的非順序性,調試可能會變得困難。需要使用專門的工具和技術來跟蹤和調試異步代碼。

  • 測試複雜性:異步代碼的測試可能更加複雜,因爲需要考慮到併發和時間依賴的因素。

  • 框架和庫的支持:在使用異步編程時,需要確保所使用的框架和庫支持異步操作,並且能夠正確地處理異步任務。

  • 性能考量:雖然異步可以提高性能,但過度使用或不當使用也可能導致性能問題。需要仔細評估和測試以確保異步操作帶來的性能提升。

  • 用戶體驗:在用戶界面程序中,適當的異步操作可以避免界面凍結,提供更好的用戶體驗。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章