最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java后端實(shí)現(xiàn)異步編程的9種方式總結(jié)

 更新時(shí)間:2025年03月27日 08:23:29   作者:撿田螺的小男孩  
我們?nèi)粘i_(kāi)發(fā)的時(shí)候,經(jīng)常說(shuō)到異步編程,比如說(shuō),在注冊(cè)接口,我們?cè)谟脩糇?cè)成功時(shí),用異步發(fā)送郵件通知用戶,那么實(shí)現(xiàn)異步編程一共有多少種方式呢,下面小編就來(lái)簡(jiǎn)單講講吧

1. 使用Thread和Runnable

Thread和Runnable是最基本的異步編程方式,直接使用Thread和Runnable來(lái)創(chuàng)建和管理線程。

public class Test {
    public static void main(String[] args) {
        System.out.println("田螺主線程:" + Thread.currentThread().getName());
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("田螺異步線程測(cè)試:"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread.start();
    }
}

但是呢,日常工作中,不推薦直接使用Thread和Runnable,因?yàn)樗羞@些缺點(diǎn):

  • 資源消耗大:每次創(chuàng)建新線程會(huì)消耗系統(tǒng)資源,頻繁創(chuàng)建和銷(xiāo)毀線程會(huì)導(dǎo)致性能下降。
  • 難以管理:手動(dòng)管理線程的生命周期、異常處理、任務(wù)調(diào)度等非常復(fù)雜。
  • 缺乏擴(kuò)展性:無(wú)法輕松控制并發(fā)線程的數(shù)量,容易導(dǎo)致系統(tǒng)資源耗盡。
  • 線程復(fù)用問(wèn)題:每次任務(wù)都創(chuàng)建新線程,無(wú)法復(fù)用已有的線程,效率低下。

2.使用Executors提供線程池

針對(duì)Thread和Runnable的缺點(diǎn),我們可以使用線程池呀,線程池主要有這些優(yōu)點(diǎn):

  • 它幫我們管理線程,避免增加創(chuàng)建線程和銷(xiāo)毀線程的資源損耗。因?yàn)榫€程其實(shí)也是一個(gè)對(duì)象,創(chuàng)建一個(gè)對(duì)象,需要經(jīng)過(guò)類(lèi)加載過(guò)程,銷(xiāo)毀一個(gè)對(duì)象,需要走GC垃圾回收流程,都是需要資源開(kāi)銷(xiāo)的。
  • 提高響應(yīng)速度。 如果任務(wù)到達(dá)了,相對(duì)于從線程池拿線程,重新去創(chuàng)建一條線程執(zhí)行,速度肯定慢很多。
  • 重復(fù)利用。 線程用完,再放回池子,可以達(dá)到重復(fù)利用的效果,節(jié)省資源。

有些小伙伴說(shuō),我們可以直接使用Executors提供的線程池呀,非常快捷方便,比如:

- Executors.newFixedThreadPool
- Executors.newCachedThreadPool

簡(jiǎn)單demo代碼如下:

public class Test {
    public static void main(String[] args) {
        System.out.println("田螺主線程:" + Thread.currentThread().getName());
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        executor.execute(()->{
            System.out.println("田螺線程池方式,異步線程:" + Thread.currentThread().getName());
        });
    }
}
//  運(yùn)行結(jié)果:
//田螺主線程:main
//田螺線程池方式,異步線程:pool-1-thread-1

3. 使用自定義線程池

使用使用Executors提供線程池,如newFixedThreadPool,雖然簡(jiǎn)單快捷,但是呢,它的阻塞隊(duì)列十無(wú)界的!

newFixedThreadPool默認(rèn)使用LinkedBlockingQueue作為任務(wù)隊(duì)列,而LinkedBlockingQueue是一個(gè)無(wú)界隊(duì)列(默認(rèn)容量為Integer.MAX_VALUE)。如果任務(wù)提交速度遠(yuǎn)大于線程池處理速度,隊(duì)列會(huì)不斷堆積任務(wù),最終可能導(dǎo)致內(nèi)存耗盡.

因此,我們一般推薦使用自定義線程池,來(lái)開(kāi)啟異步。

public class Test {
    public static void main(String[] args) {
        // 自定義線程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心線程數(shù)
                4, // 最大線程數(shù)
                60, // 空閑線程存活時(shí)間
                TimeUnit.SECONDS, // 時(shí)間單位
                new ArrayBlockingQueue<>(8), // 任務(wù)隊(duì)列
                Executors.defaultThreadFactory(), // 線程工廠
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略
        );

        System.out.println("田螺主線程:" + Thread.currentThread().getName());
        executor.execute(() -> {
            try {
                Thread.sleep(500); // 模擬耗時(shí)操作
                System.out.println("田螺自定義線程池開(kāi)啟異步:" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}
//輸出
//田螺主線程:main
//田螺自定義線程池開(kāi)啟異步:pool-1-thread-1

4. 使用Future和Callable

有些小伙伴說(shuō),如果我們期望異步編程可以返回結(jié)果呢?

那我們可以使用Future和Callable。Future和Callable是Java 5引入的,用于處理異步任務(wù)。Callable類(lèi)似于Runnable,但它可以返回一個(gè)結(jié)果,并且可以拋出異常。Future表示異步計(jì)算的結(jié)果。

簡(jiǎn)單使用demo:

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException  {
        // 自定義線程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心線程數(shù)
                4, // 最大線程數(shù)
                60, // 空閑線程存活時(shí)間
                TimeUnit.SECONDS, // 時(shí)間單位
                new ArrayBlockingQueue<>(8), // 任務(wù)隊(duì)列
                Executors.defaultThreadFactory(), // 線程工廠
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略
        );

        System.out.println("田螺主線程:" + Thread.currentThread().getName());

        Callable<String> task = () -> {
            Thread.sleep(1000); // 模擬耗時(shí)操作
            System.out.println("田螺自定義線程池開(kāi)啟異步:" + Thread.currentThread().getName());
            return "Hello, 公眾號(hào):撿田螺的小男孩!";
        };

        Future<String> future = executor.submit(task);

        String result = future.get(); // 阻塞直到任務(wù)完成
        System.out.println("異步結(jié)果:"+result);
    }
}

//運(yùn)行結(jié)果:
//田螺主線程:main
//田螺自定義線程池開(kāi)啟異步:pool-1-thread-1
//異步結(jié)果:Hello, 公眾號(hào):撿田螺的小男孩!

5. 使用CompletableFuture

CompletableFuture是Java 8引入的,提供了更強(qiáng)大的異步編程能力,支持鏈?zhǔn)秸{(diào)用、異常處理、組合多個(gè)異步任務(wù)等。

簡(jiǎn)單使用demo:

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException  {
        // 自定義線程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心線程數(shù)
                4, // 最大線程數(shù)
                60, // 空閑線程存活時(shí)間
                TimeUnit.SECONDS, // 時(shí)間單位
                new ArrayBlockingQueue<>(8), // 任務(wù)隊(duì)列
                Executors.defaultThreadFactory(), // 線程工廠
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略
        );

        System.out.println("田螺主線程:" + Thread.currentThread().getName());

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000); // 模擬耗時(shí)操作
                System.out.println("田螺CompletableFuture開(kāi)啟異步:" + Thread.currentThread().getName());
                return "Hello, 公眾號(hào):撿田螺的小男孩!";
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello, 公眾號(hào):撿田螺的小男孩!";
        },executor);

        future.thenAccept(result -> System.out.println("異步結(jié)果:" + result));
        future.join();
    }
}

6. 使用ForkJoinPool

有些時(shí)候,我們希望開(kāi)啟異步,將一個(gè)大任務(wù)拆分成多個(gè)小任務(wù)(Fork),然后將這些小任務(wù)的結(jié)果合并(Join)。這時(shí)候,我們就可以使用ForkJoinPool啦~。

ForkJoinPool 是 Java 7 引入的一個(gè)線程池實(shí)現(xiàn),專(zhuān)門(mén)用于處理分治任務(wù)。

  • 它的特點(diǎn)就是任務(wù)拆分(Fork)和結(jié)果合并(Join),以及工作竊?。╓ork-Stealing)。
  • ForkJoinPool 特別適合處理遞歸任務(wù)或可以分解的并行任務(wù)。

簡(jiǎn)單使用demo:

public class Test {
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool(); // 創(chuàng)建 ForkJoinPool
        int result = pool.invoke(new SumTask(1, 100)); // 提交任務(wù)并獲取結(jié)果
        System.out.println("1 到 100 的和為: " + result);
    }

    static class SumTask extends RecursiveTask<Integer> {
        private final int start;
        private final int end;

        SumTask(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Integer compute() {
            if (end - start <= 10) { // 直接計(jì)算小任務(wù)
                int sum = 0;
                for (int i = start; i <= end; i++) sum += i;
                return sum;
            } else { // 拆分任務(wù)
                int mid = (start + end) / 2;
                SumTask left = new SumTask(start, mid);
                SumTask right = new SumTask(mid + 1, end);
                left.fork(); // 異步執(zhí)行左任務(wù)
                return right.compute() + left.join(); // 等待左任務(wù)完成并合并結(jié)果
            }
        }
    }

}

7. Spring的@Async異步

Spring 提供了 @Async 注解來(lái)實(shí)現(xiàn)異步方法調(diào)用,非常方便。使用 @Async 可以讓方法在單獨(dú)的線程中執(zhí)行,而不會(huì)阻塞主線程。

Spring @Async 的使用步驟其實(shí)很簡(jiǎn)單:

  • 啟用異步支持:在 Spring Boot項(xiàng)目中,需要在配置類(lèi)或主應(yīng)用類(lèi)上添加 @EnableAsync 注解。
  • 標(biāo)記異步方法:在需要異步執(zhí)行的方法上添加 @Async 注解。
  • 配置線程池:默認(rèn)情況下,Spring 使用一個(gè)簡(jiǎn)單的線程池。如果需要自定義線程池,可以通過(guò)配置實(shí)現(xiàn)。

啟用異步支持

@SpringBootApplication
@EnableAsync // 啟用異步支持
public class AsyncDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncDemoApplication.class, args);
    }
}

異步服務(wù)類(lèi)

@Service
public class TianLuoAsyncService {

    @Async // 標(biāo)記為異步方法
    public void asyncTianLuoTask() {
        try {
            Thread.sleep(2000); // 模擬耗時(shí)操作
            System.out.println("異步任務(wù)完成,線程: " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

默認(rèn)情況下,Spring 使用一個(gè)簡(jiǎn)單的線程池(SimpleAsyncTaskExecutor),每次調(diào)用都會(huì)創(chuàng)建一個(gè)新線程。因此,在使用Spring的@Async進(jìn)行異步時(shí),推薦使用自定義線程池。

如下:

@Configuration
public class AsyncConfig {

    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); // 核心線程數(shù)
        executor.setMaxPoolSize(20);  // 最大線程數(shù)
        executor.setQueueCapacity(50); // 隊(duì)列容量
        executor.setThreadNamePrefix("AsyncThread-"); // 線程名前綴
        executor.initialize();
        return executor;
    }
}

然后,在 @Async 注解中指定線程池的名稱:

@Async("taskExecutor") // 指定使用自定義的線程池
public void asyncTianLuoTask() {
    // 方法邏輯
}

8. MQ實(shí)現(xiàn)異步

我們?cè)谔岬組Q的時(shí)候,經(jīng)常提到,它有異步處理、解耦、流量削鋒。 是的,MQ經(jīng)常用來(lái)實(shí)現(xiàn)異步編程

簡(jiǎn)要代碼如下:先保存用戶信息,然后發(fā)送注冊(cè)成功的MQ消息

  // 用戶注冊(cè)方法
  public void registerUser(String username, String email, String phoneNumber) {
      // 保存用戶信息(簡(jiǎn)化版)
      userService.add(buildUser(username,email,phoneNumber))
      // 發(fā)送消息
      String registrationMessage = "User " + username + " has registered successfully.";
      // 發(fā)送消息到隊(duì)列
      rabbitTemplate.convertAndSend("registrationQueue", registrationMessage);
  }

消費(fèi)者從隊(duì)列中讀取消息并發(fā)送短信或郵件

@Service
public class NotificationService {

    // 監(jiān)聽(tīng)消息隊(duì)列中的消息并發(fā)送短信/郵件
    @RabbitListener(queues = "registrationQueue")
    public void handleRegistrationNotification(String message) {
        // 這里可以進(jìn)行短信或郵件的發(fā)送操作
        System.out.println("Sending registration notification: " + message);

        // 假設(shè)這里是發(fā)送短信的操作
        sendSms(message);

        // 也可以做其他通知(比如發(fā)郵件等)
        sendEmail(message);
    }
  }

9.使用Hutool工具庫(kù)的ThreadUtil

可以使用的是類(lèi)似 Hutool 工具庫(kù)中的 ThreadUtil,它提供了豐富的線程池管理和異步任務(wù)調(diào)度功能。

先引入依賴:

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.11</version> <!-- 請(qǐng)使用最新版本 -->
</dependency>

最簡(jiǎn)單的,可以直接使用ThreadUtil.execute執(zhí)行異步任務(wù)

public class Test {
    public static void main(String[] args) {
        System.out.println("田螺主線程");
        ThreadUtil.execAsync(
                () -> {
                    System.out.println("田螺異步測(cè)試:" + Thread.currentThread().getName());
                }
        );
    }
}
//輸出
//田螺主線程
//田螺異步測(cè)試:pool-1-thread-1

以上就是Java后端實(shí)現(xiàn)異步編程的9種方式總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java異步編程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • @Transactional注解不起作用的原因分析及解決

    @Transactional注解不起作用的原因分析及解決

    這篇文章主要介紹了@Transactional注解不起作用的原因分析及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java將m3u8格式轉(zhuǎn)成視頻文件的方法

    java將m3u8格式轉(zhuǎn)成視頻文件的方法

    這篇文章主要介紹了如何java將m3u8格式轉(zhuǎn)成視頻文件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • java計(jì)算百分比值的方法

    java計(jì)算百分比值的方法

    這篇文章主要介紹了java計(jì)算百分比值的方法,涉及java數(shù)值運(yùn)算的技巧,需要的朋友可以參考下
    2015-03-03
  • 關(guān)于Java兩個(gè)浮點(diǎn)型數(shù)字加減乘除的問(wèn)題

    關(guān)于Java兩個(gè)浮點(diǎn)型數(shù)字加減乘除的問(wèn)題

    由于浮點(diǎn)數(shù)在計(jì)算機(jī)中是以二進(jìn)制表示的,直接進(jìn)行加減乘除運(yùn)算會(huì)出現(xiàn)精度誤差,想要得到精確結(jié)果,應(yīng)使用BigDecimal類(lèi)進(jìn)行運(yùn)算
    2024-10-10
  • springcloud-eureka與gateway簡(jiǎn)易搭建過(guò)程

    springcloud-eureka與gateway簡(jiǎn)易搭建過(guò)程

    文章介紹了如何搭建Eureka服務(wù)注冊(cè)中心和Spring Cloud Gateway網(wǎng)關(guān),對(duì)于Eureka,首先創(chuàng)建eureka-server項(xiàng)目,配置依賴和屬性,啟動(dòng)后通過(guò)控制臺(tái)查看服務(wù)注冊(cè)狀態(tài),對(duì)于Spring Cloud Gateway,創(chuàng)建gateway項(xiàng)目,配置依賴和屬性,啟動(dòng)后測(cè)試路由轉(zhuǎn)發(fā)功能,感興趣的朋友一起看看吧
    2025-12-12
  • javaWeb項(xiàng)目部署到阿里云服務(wù)器步驟詳解

    javaWeb項(xiàng)目部署到阿里云服務(wù)器步驟詳解

    本篇文章主要介紹了javaWeb項(xiàng)目部署到阿里云服務(wù)器步驟詳解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-05-05
  • 常見(jiàn)的排序算法,一篇就夠了

    常見(jiàn)的排序算法,一篇就夠了

    這篇文章主要介紹了一些常用排序算法整理,插入排序算法、直接插入排序、希爾排序、選擇排序、冒泡排序等排序,需要的朋友可以參考下
    2021-07-07
  • Druid連接池配置過(guò)程及連接池調(diào)優(yōu)方式

    Druid連接池配置過(guò)程及連接池調(diào)優(yōu)方式

    這篇文章主要介紹了Druid連接池配置過(guò)程及連接池調(diào)優(yōu)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-10-10
  • Java對(duì)稱加密工作模式原理詳解

    Java對(duì)稱加密工作模式原理詳解

    這篇文章主要介紹了Java對(duì)稱加密工作模式原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java類(lèi)比C++的STL庫(kù)詳解

    java類(lèi)比C++的STL庫(kù)詳解

    這篇文章主要介紹了java類(lèi)比C++的STL庫(kù)詳解,標(biāo)準(zhǔn)模板庫(kù),是C++標(biāo)準(zhǔn)庫(kù)的重要組成部分,中文可譯為標(biāo)準(zhǔn)模板庫(kù)或者泛型庫(kù),其包含有大量的模板類(lèi)和模板函數(shù),STL 是一些容器、算法和其他一些組件的集合,需要的朋友可以參考下
    2023-08-08

最新評(píng)論

台东县| 灵石县| 吴忠市| 贺兰县| 宝清县| 定日县| 广德县| 大渡口区| 临朐县| 改则县| 喀什市| 和田县| 黄大仙区| 江油市| 永清县| 上犹县| 清镇市| 电白县| 高阳县| 黎川县| 瑞丽市| 建水县| 改则县| 山东省| 响水县| 大丰市| 黔西| 临夏县| 崇信县| 高尔夫| 揭东县| 叙永县| 公主岭市| 乃东县| 开化县| 建德市| 黔西县| 镇巴县| 武胜县| 桂阳县| 泾川县|