国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

第一次使用ThreadPoolTaskExecutor實(shí)現(xiàn)線程池的經(jīng)歷,反復(fù)修改了多次代碼才正常使用

這篇具有很好參考價(jià)值的文章主要介紹了第一次使用ThreadPoolTaskExecutor實(shí)現(xiàn)線程池的經(jīng)歷,反復(fù)修改了多次代碼才正常使用。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1、前言

??在一個(gè)向第三方平臺(tái)推送消息的場(chǎng)景中,為了提高程序的執(zhí)行效率,每次發(fā)送消息,都創(chuàng)建一個(gè)新的線程來(lái)完成發(fā)送消息的任務(wù),為了提供線程的使用性能,我選擇了ThreadPoolTaskExecutor線程池,結(jié)果在使用的過(guò)程中,出現(xiàn)了較多的問(wèn)題,這里記錄一下避免以后再出現(xiàn)類似的錯(cuò)誤(這些錯(cuò)誤是不應(yīng)該出現(xiàn)的,還是對(duì)ThreadPoolTaskExecutor使用不熟悉造成的)。

2、ThreadPoolTaskExecutor用法簡(jiǎn)介

??ThreadPoolTaskExecutor是Spring Framework提供的一個(gè)線程池實(shí)現(xiàn),它繼承自ThreadPoolExecutor類,并實(shí)現(xiàn)了AsyncTaskExecutor和SchedulingTaskExecutor接口,可以用于異步任務(wù)執(zhí)行和定時(shí)任務(wù)調(diào)度。
??我們通過(guò)配置類定義了一個(gè)ThreadPoolTaskExecutor的Bean,并設(shè)置了核心線程數(shù)、最大線程數(shù)、隊(duì)列容量和線程名稱前綴等參數(shù)。然后在MyService類中注入了這個(gè)線程池,并在executeTask方法中使用taskExecutor.execute()來(lái)提交一個(gè)異步任務(wù)。
??通過(guò)這種方式,我們可以方便地使用ThreadPoolTaskExecutor來(lái)執(zhí)行異步任務(wù),實(shí)現(xiàn)多線程處理和任務(wù)調(diào)度的功能。

??以下是ThreadPoolTaskExecutor的基本用法示例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class ExecutorConfig {
    
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("MyThread-");
        executor.initialize();
        return executor;
    }
}

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

@Component
public class MyService {

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    public void executeTask() {
        taskExecutor.execute(() -> {
            // 執(zhí)行異步任務(wù)邏輯
            // ...
        });
    }
}

3、ThreadPoolTaskExecutor使用過(guò)程復(fù)現(xiàn)

3.1、最開始的代碼——線程泄露

??以下代碼是最開始的一版代碼,這里出現(xiàn)了一個(gè)非常嚴(yán)重的錯(cuò)誤,直接造成了線程泄露,或者說(shuō)是完全錯(cuò)用了線程池,反而造成了更多的線程資源浪費(fèi)。

/**
 * 消息推送
 * 20230609 hsh
 */
public class PushNotificationService {

    private static Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    /**
     * 線程池
     * @return
     */
    public static Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(1000);
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
    /**
     * 消息推送
     */
    public static void pushNotification(EventTask eventTask, Map<String,Object> param) {
       Executor executor = getAsyncExecutor();
       executor.execute(new Runnable() {
           @Override
           public void run() {
                if(this.isSend(param)){//判斷是否需要推送
                   String msg = "";
                   sendMsg(eventInfo);
                }
           }

           private boolean isSend(Map<String, Object> param) {
                
               return true;
           }
           private String sendMsg(String msg){
               
               return "發(fā)送";
           }
       });
    }

}

??上述代碼的問(wèn)題,主要發(fā)生在獲取線程池的問(wèn)題上,即每次發(fā)送消息都調(diào)用了getAsyncExecutor()方法,本意是獲取一個(gè)線程,結(jié)果這里每次都會(huì)創(chuàng)建一個(gè)線程池,而且線程數(shù)至少會(huì)有10個(gè),所以每次本來(lái)只需要?jiǎng)?chuàng)建一個(gè)線程處理消息發(fā)送,結(jié)果每次都創(chuàng)建了一個(gè)線程池,每個(gè)線程池至少還有10個(gè)線程,結(jié)果就出現(xiàn)了線程泄露問(wèn)題。

3.2、第一次修改——解決線程泄露問(wèn)題,但是線程不安全,在多線程環(huán)境下還是可能會(huì)導(dǎo)致創(chuàng)建多個(gè)線程池實(shí)例

??為了解決最開始出現(xiàn)的線程泄露問(wèn)題,我把ThreadPoolTaskExecutor 作為對(duì)象的一個(gè)變量,每次獲取的時(shí)候,判斷是否為空,如果不為空時(shí),就不再創(chuàng)建了。

/**
 * 消息推送
 * 20230609 hsh
 */
public class PushNotificationService {

    private static Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    
	private static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    /**
     * 線程池
     * @return
     */
    public static Executor getAsyncExecutor() {
    	if(executor == null){
            executor = new ThreadPoolTaskExecutor();
        }
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(1000);
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
    //省略……

}

??如果多個(gè)線程同時(shí)調(diào)用getAsyncExecutor()方法,還是可能會(huì)導(dǎo)致創(chuàng)建多個(gè)線程池實(shí)例。

3.3、第二次修改——解決線程安全問(wèn)題,帶來(lái)了性能問(wèn)題

??為了解決線程安全問(wèn)題,我直接使用了synchronized 關(guān)鍵字,代碼如下:

/**
 * 消息推送
 * 20230609 hsh
 */
public class PushNotificationService {

    private static Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    
	private static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    /**
     * 線程池
     * @return
     */
    public static Executor getAsyncExecutor() {
    	 synchronized (executor){
            if(executor == null){
                executor = new ThreadPoolTaskExecutor();
            }
            executor.setCorePoolSize(30);
            executor.setMaxPoolSize(100);
            executor.setQueueCapacity(1000);
            executor.setThreadNamePrefix("AsyncThread-");
            executor.initialize();
            return executor;
        }
    }
    //省略……
}

??為了解決線程安全問(wèn)題,我直接使用了synchronized 關(guān)鍵字,上述代碼雖然可以正常運(yùn)行,但是帶來(lái)了非常嚴(yán)重的性能問(wèn)題,因?yàn)閟ynchronized 關(guān)鍵字包含了整個(gè)代碼塊,就相當(dāng)于在getAsyncExecutor() 方法上使用了synchronized 關(guān)鍵字,該方法就變成了單線程執(zhí)行了,所以效率非常低。

3.4、第二次修改——解決性能問(wèn)題,帶來(lái)了初始化異常

??為了解決性能問(wèn)題,使用雙重檢查鎖定(double-checked locking)機(jī)制來(lái)確保線程安全同時(shí)保證處理性能,代碼如下:

/**
 * 消息推送
 * 20230609 hsh
 */
public class PushNotificationService {

    private static Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    
	private static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    /**
     * 線程池
     * @return
     */
    public static Executor getAsyncExecutor() {
    	 if (executor == null) {
            synchronized (executor) {
                if (executor == null) {
                    executor = new ThreadPoolTaskExecutor();
                    executor.setCorePoolSize(30);
                    executor.setMaxPoolSize(100);
                    executor.setQueueCapacity(1000);
                    executor.setThreadNamePrefix("AsyncThread-");
                    executor.initialize();
                }
            }
        }
        return executor;
    }
    //省略……
}

??通過(guò)雙重檢查鎖定,確實(shí)可以實(shí)現(xiàn)性能的提升,但是這里忽略了一個(gè)細(xì)節(jié),就是ThreadPoolTaskExecutor 初始化,因?yàn)檫@里當(dāng)executor 對(duì)象不為空時(shí),直接返回了,沒(méi)有進(jìn)行initialize()操作,所以報(bào)了“ThreadPoolTaskExecutor not initialized ”錯(cuò)誤,因此聲明ThreadPoolTaskExecutor executor 對(duì)象的時(shí)候,不能使用new ThreadPoolTaskExecutor()方法進(jìn)行定義,同時(shí)為了避免指令重排序可能帶來(lái)的問(wèn)題,需要將 executor 聲明為 volatile 類型,以確保在多線程環(huán)境下的可見性和正確的初始化順序。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-481550.html

/**
 * 消息推送
 * 20230609 hsh
 */
public class PushNotificationService {

    private static Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    
	private static volatile ThreadPoolTaskExecutor executor;
    /**
     * 線程池
     * @return
     */
    public static Executor getAsyncExecutor() {
    	 if (executor == null) {
            synchronized (executor) {
                if (executor == null) {
                    executor = new ThreadPoolTaskExecutor();
                    executor.setCorePoolSize(30);
                    executor.setMaxPoolSize(100);
                    executor.setQueueCapacity(1000);
                    executor.setThreadNamePrefix("AsyncThread-");
                    executor.initialize();
                }
            }
        }
        return executor;
    }
    //省略……
}

4、總結(jié)

  1. 知識(shí)點(diǎn)1:ThreadPoolTaskExecutor用法
  2. 知識(shí)點(diǎn)2:synchronized 關(guān)鍵字
  3. 知識(shí)點(diǎn)3:雙重檢查鎖定(double-checked locking)機(jī)制
  4. 知識(shí)點(diǎn)4:volatile 關(guān)鍵字

到了這里,關(guān)于第一次使用ThreadPoolTaskExecutor實(shí)現(xiàn)線程池的經(jīng)歷,反復(fù)修改了多次代碼才正常使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • MidJourney使用教程:一 第一次怎么用Midjourney

    MidJourney使用教程:一 第一次怎么用Midjourney

    實(shí)際我是先寫的prompts提示這部分,覺得Midjurney使用的方式,市面上已經(jīng)有一大把文章了,另一方面覺得也沒(méi)什么可寫的。注冊(cè)一個(gè)discard賬號(hào)寫個(gè)prompts描述出圖就可以了,但其實(shí)有很多點(diǎn)其實(shí)忽略掉。比如圖出來(lái)了,這四幅圖底下的U1到U4,V1到V4什么意思?還有就是公共頻道

    2024年02月11日
    瀏覽(21)
  • 第一次使用HbuilderX運(yùn)行微信小程序項(xiàng)目

    第一次使用HbuilderX運(yùn)行微信小程序項(xiàng)目

    ?點(diǎn)擊設(shè)置 ?再點(diǎn)擊運(yùn)行配置,找到小程序運(yùn)行配置,設(shè)置自己對(duì)應(yīng)的路徑 如果沒(méi)有配置路徑,則會(huì)報(bào)錯(cuò): ?然后粘貼自己的appid就好了

    2024年02月13日
    瀏覽(22)
  • 華為卡托E3276s-150第一次使用怎么配置?

    最近買了有一個(gè)電信的4G網(wǎng)卡,型號(hào)是E3276s-150,由于很多朋友第一次使用的時(shí)候不知道該怎么配置,導(dǎo)致無(wú)法正常使用4G上網(wǎng),現(xiàn)將我的配置方法分享給大家。 1、故障現(xiàn)象 ?? 第一次使用電信4G上網(wǎng)卡不知道怎么配置,無(wú)法正常使用4G上網(wǎng) 2、故障判斷 ?? 網(wǎng)卡本身無(wú)問(wèn)題,客

    2024年02月08日
    瀏覽(27)
  • Spring Boot實(shí)現(xiàn)第一次啟動(dòng)時(shí)自動(dòng)初始化數(shù)據(jù)庫(kù)

    Spring Boot實(shí)現(xiàn)第一次啟動(dòng)時(shí)自動(dòng)初始化數(shù)據(jù)庫(kù)

    在現(xiàn)在的后端開發(fā)中,只要是運(yùn)用聯(lián)系型數(shù)據(jù)庫(kù),信任SSM架構(gòu)(Spring Boot + MyBatis)已經(jīng)成為首選。 不過(guò)在咱們第一次運(yùn)轉(zhuǎn)或許布置項(xiàng)目的時(shí)分,一般要先手動(dòng)銜接數(shù)據(jù)庫(kù),履行一個(gè)SQL文件以創(chuàng)立數(shù)據(jù)庫(kù)以及數(shù)據(jù)庫(kù)表格完結(jié) 數(shù)據(jù)庫(kù)的初始化作業(yè) ,這樣咱們的SSM應(yīng)用程序才能夠

    2024年02月03日
    瀏覽(24)
  • 第一次使用git將遠(yuǎn)程倉(cāng)庫(kù)的代碼拉取到本地

    第一次使用git將遠(yuǎn)程倉(cāng)庫(kù)的代碼拉取到本地

    首先默認(rèn)你已經(jīng)安裝好了git的客戶端,如果沒(méi)安裝請(qǐng)先確保已經(jīng)安裝了git的客戶端再進(jìn)行后續(xù)的操作 第一步:進(jìn)入你要克隆的文件夾下,然后點(diǎn)擊Git Bash Here 第二步:找到遠(yuǎn)程倉(cāng)庫(kù)的地址,并復(fù)制該地址(這里以github上的舉例) 第三步:使用下面的git命令從遠(yuǎn)程倉(cāng)庫(kù)復(fù)制代碼到本

    2024年02月11日
    瀏覽(95)
  • 在Windows第一次使用使用vcpkg來(lái)安裝三方庫(kù),例如nanomsg、nng、libpqxx

    在Windows第一次使用使用vcpkg來(lái)安裝三方庫(kù),例如nanomsg、nng、libpqxx

    夠早了吧 需要從github上找三方庫(kù)來(lái)使用,看了許多教程后決定為后來(lái)者寫點(diǎn)簡(jiǎn)單的流程。記得先裝git,安裝git教程如下: 到官網(wǎng)下載git添加鏈接描述 點(diǎn)擊下載然后安裝。 安裝完后會(huì)有一系列的應(yīng)用可以使用 我們主要用的是Git Bash。 vcpkg是微軟的包管理工具,可以直接下載三

    2023年04月20日
    瀏覽(27)
  • 使用git工具上傳代碼,超細(xì)講解,針對(duì)第一次玩git的小伙伴

    第一步安裝git管理工具 首先我們要去git官網(wǎng)下載git 安裝過(guò)的小伙伴可以跳過(guò)這步 創(chuàng)建一個(gè)文件 git clone 遠(yuǎn)程代碼地址 用來(lái)克隆別人寫的項(xiàng)目 或者找一個(gè)你想上傳代碼的文件夾,點(diǎn)進(jìn)文件里面,右擊打開,找的Git Bash打開 origin 遠(yuǎn)程倉(cāng)庫(kù)名,可以換成別的名稱 master 遠(yuǎn)程倉(cāng)庫(kù)主

    2024年02月07日
    瀏覽(31)
  • 當(dāng)我第一次通過(guò)Kotlin和Compose來(lái)實(shí)現(xiàn)一個(gè)Canvas時(shí), 我收獲了什么?

    自從2019年Google推薦Kotlin為Android開發(fā)的首選語(yǔ)言以來(lái)已經(jīng)經(jīng)歷了將近四年的時(shí)間, Compose的1.0版本也發(fā)布了將近2年的時(shí)間, Kotlin+Compose在現(xiàn)階段的Android開發(fā)過(guò)程中還遠(yuǎn)遠(yuǎn)達(dá)不到主流的程度. 我們是否應(yīng)該開始嘗試這個(gè)組合? 這個(gè)組合有會(huì)給我們帶來(lái)什么? 對(duì)于我來(lái)說(shuō), 我是個(gè)守舊又

    2023年04月27日
    瀏覽(24)
  • 【入門/小白向】第一次在Linux/Ubuntu終端上使用Git拉取代碼,該怎么做?保姆教程,步驟分解。

    【入門/小白向】第一次在Linux/Ubuntu終端上使用Git拉取代碼,該怎么做?保姆教程,步驟分解。

    【Step.1】 安裝 git 安裝完成后執(zhí)行下句,可以看到安裝版本: 【Step.2】 配置郵箱 (git網(wǎng)站賬戶注冊(cè)的郵箱,如bob2023@yy.com)?和用戶名 (任取,如bob): 隨后可執(zhí)行下句,查看是否配置成功: 實(shí)例執(zhí)行如下圖: ?【 Step.3 】生成 SSH 密鑰,用于遠(yuǎn)程訪問(wèn)?git (下面使用的公鑰算法是

    2024年02月05日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包