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

springboot自帶線程池ThreadPoolTaskExecutor使用

 更新時間:2023年04月07日 10:25:59   作者:luffy5459  
本文主要介紹了springboot自帶線程池ThreadPoolTaskExecutor使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

不管是阿里,還是華為java開發(fā)手冊,都會有一條建議,就是讓開發(fā)者不要使用Executors去創(chuàng)建線程池,而是使用構(gòu)造函數(shù)ThreadPoolExecutor的方式來創(chuàng)建,并設(shè)置合理的參數(shù)。原因如下:

     說明:Executors 返回的線程池對象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:
允許的請求隊列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導(dǎo)致 OOM。
2) CachedThreadPool:
允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE,可能會創(chuàng)建大量的線程,從而導(dǎo)致 OOM。

在spring框架中,spring提供了ThreadPoolTaskExecutor來創(chuàng)建線程池,該類在spring-context包下。其實ThreadPoolTaskExecutor是對ThreadPoolExecutor的封裝。

到了springboot這里,因為引入了spring-boot-autoconfigurer,自動裝配機制,在task包下,直接把ThreadPoolTaskExecutor注入到bean容器里面。所以在springboot項目中,如果要使用線程池,可以直接使用,都不用額外任何配置。

springboot自動裝配的線程池使用的配置如下:

默認核心線程數(shù)是8個。最大線程數(shù)和等待隊列都是Integer.MAX_VALUE。綜合上面的介紹,默認配置的線程池其實也有OOM的風(fēng)險。 

這里使用的springboot版本是2.7.8。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.example</groupId>
    <artifactId>springexample</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.8</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.20</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
 
</project>

異步任務(wù)類:在方法上添加@Async注解,可以讓他啟用線程池處理異步任務(wù)。

/*
 *    xxx co.ltd Copyright @ 2023-2023 All Rights Reserved
 */
 
package com.example.task;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
 
import java.util.Random;
import java.util.concurrent.CompletableFuture;
 
/**
 * 描述信息
 *
 * @author Administrator
 * @since 2023/4/2 7:30
 */
@Slf4j
@Component
public class AsyncTask {
    private Random random = new Random();
 
    @Async
    public CompletableFuture<String> doTaskOne() throws Exception {
        log.info("task one start.");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("task one done,cost " + (end - start) + "ms.");
        return CompletableFuture.completedFuture("task one done");
    }
 
    @Async
    public CompletableFuture<String> doTaskTwo() throws Exception {
        log.info("task two start.");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("task two done,cost " + (end - start) + "ms.");
        return CompletableFuture.completedFuture("task two done");
    }
 
    @Async
    public CompletableFuture<String> doTaskThree() throws Exception {
        log.info("task three start.");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("task three done,cost " + (end - start) + "ms.");
        return CompletableFuture.completedFuture("task three done");
    }
}

啟動類:啟動類上添加注解@EnableAsync開啟異步

/*
 *    xxx co.ltd Copyright @ 2023-2023 All Rights Reserved
 */
 
package com.example;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
 
/**
 * 描述信息
 *
 * @author Administrator
 * @since 2023/4/2 7:29
 */
@SpringBootApplication
@EnableAsync
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

測試類:

/*
 *    xxx co.ltd Copyright @ 2023-2023 All Rights Reserved
 */
 
package com.example.task;
 
import com.example.App;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
 
import java.util.concurrent.CompletableFuture;
 
/**
 * 描述信息
 *
 * @author Administrator
 * @since 2023/4/2 7:34
 */
@SpringBootTest(classes = {App.class})
@Slf4j
public class AsyncTaskTest {
 
    @Autowired
    private AsyncTask asyncTask;
 
    @Test
    public void testTask() throws Exception {
        long start = System.currentTimeMillis();
        CompletableFuture<String> taskOne = asyncTask.doTaskOne();
        CompletableFuture<String> taskTwo = asyncTask.doTaskTwo();
        CompletableFuture<String> taskThree = asyncTask.doTaskThree();
        CompletableFuture.allOf(taskOne, taskTwo, taskThree).join();
        long end = System.currentTimeMillis();
        log.info("all task done,cost " + (end - start) + " ms");
    }
}

這里設(shè)置了3個任務(wù),默認線程池核心線程數(shù)是8個, 所以這3個任務(wù)在線程池環(huán)境中,基本都是同時運行,所以總體運行時間肯定會大于他們3各種最耗時的一個任務(wù),小于三個任務(wù)耗時之和。

運行這個測試用例,打印結(jié)果:

從打印結(jié)果來看,3個任務(wù)幾乎同時執(zhí)行,運行結(jié)束,分別耗時:2094ms、 653ms、 1505ms,最后總耗時2129ms,符合預(yù)期。 

這里打印的線程池前綴是task-,也是默認線程池配置。

在springboot配置中,提供了可以配置線程池的參數(shù):

spring:
  task:
    execution:
      pool:
        core-size: 2
        max-size: 5
        queue-capacity: 10
      thread-name-prefix: test-task-

這些參數(shù)都不是我們自定義的,而是springboot配置文件中指定的參數(shù)名。所以我們可以通過yml自動提示類進行配置:

這里也可以看出默認線程池配置核心數(shù)量是8個, 這里我們設(shè)置為2,來驗證線程池工作原理。

這里有3個任務(wù),核心線程數(shù)是2,所以只能先執(zhí)行2個任務(wù),剩下的進入隊列等待,當前面一個任務(wù)執(zhí)行完成,最后一個任務(wù)才會從等待隊列中進入核心線程進行執(zhí)行,重新運行單元測試,打印信息如下:

這個打印結(jié)果,剛開始任務(wù)1,2都運行,任務(wù)2完成之后,任務(wù)3開始執(zhí)行。

因為修改了線程前綴,這里打印的線程前綴是test-task-,從線程前綴 + 線程數(shù)上來看,這里最大線程數(shù)是2,因為前面設(shè)置的核心線程數(shù)就是2。

相信做過springboot線程池相關(guān)的測試,可能有的人得出的結(jié)論和我這里不太一樣,springboot默認線程池是SimpleAsyncTaskExecutor。這個原因呢,有兩個,一個是springboot版本的原因,默認不做任何配置,一樣的代碼,上面運行打印的線程池前綴就是SimpleAsyncTaskExecutor。另外一個原因就是上面提到的ThreadPoolTaskExecutor在配置的時候,其實使用了一個特別的注解:@ConditionalOnMissingBean({Executor.class}),如下所示:

這個注解的意思是,當bean容器中沒有Executor.class這個實例的時候,進行配置。也即是說其他地方配置了線程器Executor,那么這個ThreadPoolTaskExecutor的bean就不會被配置。這也就是大家的結(jié)論里面spring線程池默認不是ThreadPoolTaskExecutor的原因。

我這里通過引入spring-boot-starter-websocket依賴,然后配置websocket:

/*
 *    xxx co.ltd Copyright @ 2023-2023 All Rights Reserved
 */
 
package com.example.config;
 
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
 
/**
 * 描述信息
 *
 * @author Administrator
 * @since 2023/4/2 20:14
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/tmax/ws").setAllowedOriginPatterns("*").withSockJS();
    }
 
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/user","/topic");
        registry.setApplicationDestinationPrefixes("/app");
        registry.setUserDestinationPrefix("/user");
    }
}

同樣的,我們再次測試,發(fā)現(xiàn)結(jié)果如下所示:

這里也驗證了上面@ConditionalOnMissingBean({Executor.class})注解的作用,因為有了別的線程池,所以這里ThreadPoolTaskExecutor線程池就沒有被加載。這里的線程池就是SimpleAsyncTaskExecutor。這個線程池其實不是一個真正的線程池,因為它每次都會創(chuàng)建新線程,這個線程池創(chuàng)建的目的其實就是為了執(zhí)行少量短時間的任務(wù),并不適合在高并發(fā)場景下。

通過上面的實驗,我們知道,在springboot 2.7.8版本里面,如果沒有其他配置,默認線程池就是ThreadPoolTaskExecutor,而且可以不用任何配置就可以使用。但是它還是有OOM的風(fēng)險,因為它的max-size和queue-capacity都是Integer.MAX_VALUE,所以我們需要修改它的默認線程池配置信息。但是默認線程池有個德性,就是如果配置了其他線程池,它又不會被加載。

所以一般的項目里面,我們都是進行如下所示的手動配置:

/*
 *    xxx co.ltd Copyright @ 2023-2023 All Rights Reserved
 */
 
package com.example.config;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
import java.util.concurrent.ThreadPoolExecutor;
 
/**
 * 描述信息
 *
 * @author Administrator
 * @since 2023/4/2 20:36
 */
@Configuration
@EnableAsync
public class ThreadPoolConfig {
    @Value("${spring.task.execution.pool.core-size}")
    private int corePoolSize;
    @Value("${spring.task.execution.pool.max-size}")
    private int maxPoolSize;
    @Value("${spring.task.execution.pool.queue-capacity}")
    private int queueCapacity;
    @Value("${spring.task.execution.thread-name-prefix}")
    private String threadNamePrefix;
 
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix(threadNamePrefix);
        // 拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }
}

另外,一定要結(jié)合application.yml中設(shè)置的線程池配置信息使用,這樣才符合文章開頭所說的大廠java開發(fā)手冊中建議使用自定義參數(shù)配置線程池,避免OOM風(fēng)險。 

到此這篇關(guān)于springboot自帶線程池ThreadPoolTaskExecutor使用的文章就介紹到這了,更多相關(guān)springboot ThreadPoolTaskExecutor 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot mybatis druid配置多數(shù)據(jù)源教程

    springboot mybatis druid配置多數(shù)據(jù)源教程

    這篇文章主要介紹了springboot mybatis druid配置多數(shù)據(jù)源教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java實現(xiàn)按層遍歷二叉樹

    java實現(xiàn)按層遍歷二叉樹

    這篇文章主要為大家詳細介紹了java實現(xiàn)按層遍歷二叉樹,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • SpringBoot整合MongoDB的步驟詳解

    SpringBoot整合MongoDB的步驟詳解

    這篇文章主要介紹了SpringBoot整合MongoDB的步驟詳解,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下
    2021-04-04
  • java中for循環(huán)執(zhí)行的順序圖文詳析

    java中for循環(huán)執(zhí)行的順序圖文詳析

    關(guān)于java的for循環(huán)想必大家非常熟悉,它是java常用的語句之一,這篇文章主要給大家介紹了關(guān)于java中for循環(huán)執(zhí)行順序的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • sharding-jdbc5.0.0實現(xiàn)分表實踐

    sharding-jdbc5.0.0實現(xiàn)分表實踐

    本文主要介紹了sharding-jdbc5.0.0分表實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Java的類型擦除式泛型詳解

    Java的類型擦除式泛型詳解

    Java語言中的泛型只存在于程序源碼之中,在編譯后的字節(jié)碼文件里,則全部泛型都會被替換為原來的原始類型(Raw Type),并且會在相應(yīng)的地方插入強制轉(zhuǎn)型的代碼。這篇文章主要介紹了Java的類型擦除式泛型,需要的朋友可以參考下
    2021-08-08
  • 聊聊SpringBoot使用Nacos進行服務(wù)注冊發(fā)現(xiàn)與配置管理問題

    聊聊SpringBoot使用Nacos進行服務(wù)注冊發(fā)現(xiàn)與配置管理問題

    Nacos支持基于DNS和基于RPC的服務(wù)發(fā)現(xiàn)(可以作為springcloud的注冊中心)、動態(tài)配置服務(wù)(可以做配置中心)、動態(tài)?DNS?服務(wù)。本文重點給大家介紹SpringBoot使用Nacos進行服務(wù)注冊發(fā)現(xiàn)與配置管理,感興趣的朋友一起看看吧
    2022-01-01
  • Java匿名類,匿名內(nèi)部類實例分析

    Java匿名類,匿名內(nèi)部類實例分析

    這篇文章主要介紹了Java匿名類,匿名內(nèi)部類,結(jié)合實例形式分析了Java匿名類,匿名內(nèi)部類相關(guān)原理、用法及操作注意事項,需要的朋友可以參考下
    2020-04-04
  • java實現(xiàn)簡單驗證碼生成

    java實現(xiàn)簡單驗證碼生成

    這篇文章主要介紹了java實現(xiàn)簡單驗證碼生成,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • SpringCloud集成AlloyDB的示例代碼

    SpringCloud集成AlloyDB的示例代碼

    AlloyDB?是?Google?Cloud?提供的一種高度可擴展、強性能的關(guān)系型數(shù)據(jù)庫服務(wù),它兼容?PostgreSQL,并提供了更快的查詢性能和更高的可用性,本文給大家介紹了如何使用SpringCloud集成AlloyDB,需要的朋友可以參考下
    2025-01-01

最新評論

巩义市| 镶黄旗| 临汾市| 马山县| 黑河市| 岳阳县| 油尖旺区| 儋州市| 阳原县| 新昌县| 文登市| 东阿县| 凤阳县| 凤阳县| 东丽区| 赤水市| 大理市| 长岭县| 乐清市| 新宁县| 常熟市| 平武县| 三台县| 威远县| 衡水市| 黎平县| 夹江县| 江达县| 华阴市| 无为县| 沁源县| 龙州县| 岫岩| 鄂尔多斯市| 岑溪市| 辽中县| 米泉市| 溆浦县| 泸水县| 利津县| 大荔县|