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

SpringBoot中定時(shí)任務(wù)@Scheduled的多線程使用詳解

 更新時(shí)間:2023年04月21日 16:38:49   作者:Cosolar  
這篇文章主要為大家詳細(xì)介紹了pring Boot定時(shí)任務(wù)@Scheduled的多線程原理以及如何加入線程池來(lái)處理定時(shí)任務(wù),感興趣的可以了解一下

一、@Scheduled注解簡(jiǎn)介

@Scheduled是Spring框架中的一個(gè)注解,它可以用于配置定時(shí)任務(wù),使得方法可以按照規(guī)定的時(shí)間間隔定時(shí)執(zhí)行。在使用該注解時(shí),我們可以指定任務(wù)的執(zhí)行時(shí)間、循環(huán)周期、并發(fā)數(shù)等參數(shù),從而實(shí)現(xiàn)定時(shí)任務(wù)的功能。在Spring Boot中,@Scheduled注解可以直接應(yīng)用于方法上。

二、@Scheduled的多線程機(jī)制

在Spring Boot中,@Scheduled注解是基f于Java的ThreadPoolExecutor和ScheduledThreadPoolExecutor實(shí)現(xiàn)的。當(dāng)我們配置了一個(gè)定時(shí)任務(wù)后,Spring Boot會(huì)首先創(chuàng)建一個(gè)ScheduledThreadPoolExecutor線程池,并將定時(shí)任務(wù)添加到該線程池中等待執(zhí)行。然后,在指定的時(shí)間到來(lái)之后,線程池會(huì)為該定時(shí)任務(wù)分配一個(gè)線程來(lái)執(zhí)行。如果該定時(shí)任務(wù)還未執(zhí)行完畢,在下一個(gè)周期到達(dá)時(shí),線程池會(huì)為該任務(wù)再次分配一個(gè)線程來(lái)執(zhí)行。通過(guò)這種方式,@Scheduled可以非常方便地實(shí)現(xiàn)周期性的定時(shí)任務(wù)f于Java的ThreadPoolExecutor和ScheduledThreadPoolExecutor實(shí)現(xiàn)的。當(dāng)我們配置了一個(gè)定時(shí)任務(wù)后,Spring Boot會(huì)首先創(chuàng)建一個(gè)ScheduledThreadPoolExecutor線程池,并將定時(shí)任務(wù)添加到該線程池中等待執(zhí)行。然后,在指定的時(shí)間到來(lái)之后,線程池會(huì)為該定時(shí)任務(wù)分配一個(gè)線程來(lái)執(zhí)行。如果該定時(shí)任務(wù)還未執(zhí)行完畢,在下一個(gè)周期到達(dá)時(shí),線程池會(huì)為該任務(wù)再次分配一個(gè)線程來(lái)執(zhí)行。通過(guò)這種方式,@Scheduled可以非常方便地實(shí)現(xiàn)周期性的定時(shí)任務(wù)。

三、@Scheduled的多線程問(wèn)題

雖然@Scheduled注解非常便捷,但是它也存在一些多線程的問(wèn)題,主要體現(xiàn)在以下兩個(gè)方面:

1.定時(shí)任務(wù)未執(zhí)行完畢時(shí),后續(xù)任務(wù)可能會(huì)受到影響

在使用@Scheduled注解時(shí),我們很容易忽略一個(gè)問(wèn)題:如果定時(shí)任務(wù)在執(zhí)行時(shí),下一個(gè)周期的任務(wù)已經(jīng)到了,那么后續(xù)任務(wù)可能會(huì)受到影響。例如,我們定義了一個(gè)間隔時(shí)間為5秒的定時(shí)任務(wù)A,在第1秒時(shí)開(kāi)始執(zhí)行,需要執(zhí)行10秒鐘。在第6秒時(shí),定時(shí)任務(wù)A還沒(méi)有結(jié)束,此時(shí)下一個(gè)周期的任務(wù)B已經(jīng)開(kāi)始等待執(zhí)行。如果此時(shí)線程池中沒(méi)有足夠的空閑線程,那么定時(shí)任務(wù)B就會(huì)被阻塞,無(wú)法執(zhí)行。

2.多個(gè)定時(shí)任務(wù)并發(fā)執(zhí)行可能導(dǎo)致資源競(jìng)爭(zhēng)

在某些情況下,我們可能需要編寫(xiě)多個(gè)定時(shí)任務(wù),這些定時(shí)任務(wù)可能涉及到共享資源,例如數(shù)據(jù)庫(kù)連接、緩存對(duì)象等。當(dāng)多個(gè)定時(shí)任務(wù)同時(shí)執(zhí)行時(shí),就會(huì)存在資源競(jìng)爭(zhēng)的問(wèn)題,可能會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)誤或者系統(tǒng)崩潰。

四、@Scheduled加入線程池來(lái)處理定時(shí)任務(wù)

為了避免上述問(wèn)題,可以將@Scheduled任務(wù)交給線程池進(jìn)行處理。在Spring Boot中,可以通過(guò)以下兩種方式來(lái)將@Scheduled任務(wù)加入線程池:

1.使用@EnableScheduling + @Configuration配置ThreadPoolTaskScheduler

@Configuration
@EnableScheduling
public class TaskSchedulerConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10);
        scheduler.initialize();
        return scheduler;
    }
}

在上述代碼中,我們通過(guò)配置ThreadPoolTaskScheduler來(lái)創(chuàng)建一個(gè)線程池,并使用@EnableScheduling注解將定時(shí)任務(wù)開(kāi)啟。其中,setPoolSize方法可以設(shè)置線程池的大小,默認(rèn)為1。

2.使用ThreadPoolTaskExecutor

@Configuration
@EnableScheduling
public class TaskExecutorConfig {
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(1000);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("task-executor-");
        return executor;
    }
}

在上述代碼中,我們通過(guò)配置ThreadPoolTaskExecutor來(lái)創(chuàng)建一個(gè)線程池,并使用@EnableScheduling注解將定時(shí)任務(wù)開(kāi)啟。其中setCorePoolSize、setMaxPoolSize、setQueueCapacity、setKeepAliveSeconds等方法可以用于配置線程池的大小和任務(wù)隊(duì)列等參數(shù)。

五、@Scheduled詳細(xì)分析

在Spring Boot中,@Scheduled注解是基于Java的ThreadPoolExecutor和ScheduledThreadPoolExecutor實(shí)現(xiàn)的。當(dāng)我們配置了一個(gè)定時(shí)任務(wù)后,Spring Boot會(huì)首先創(chuàng)建一個(gè)ScheduledThreadPoolExecutor線程池,并將定時(shí)任務(wù)添加到該線程池中等待執(zhí)行。然后,在指定的時(shí)間到來(lái)之后,線程池會(huì)為該定時(shí)任務(wù)分配一個(gè)線程來(lái)執(zhí)行。如果該定時(shí)任務(wù)還未執(zhí)行完畢,在下一個(gè)周期到達(dá)時(shí),線程池會(huì)為該任務(wù)再次分配一個(gè)線程來(lái)執(zhí)行。通過(guò)這種方式,@Scheduled可以非常方便地實(shí)現(xiàn)周期性的定時(shí)任務(wù)。

雖然@Scheduled注解非常便捷,但是它也存在一些多線程的問(wèn)題,主要體現(xiàn)在以下兩個(gè)方面:

1. 定時(shí)任務(wù)未執(zhí)行完畢時(shí),后續(xù)任務(wù)可能會(huì)受到影響

在使用@Scheduled注解時(shí),我們很容易忽略一個(gè)問(wèn)題:如果定時(shí)任務(wù)在執(zhí)行時(shí),下一個(gè)周期的任務(wù)已經(jīng)到了,那么后續(xù)任務(wù)可能會(huì)受到影響。例如,我們定義了一個(gè)間隔時(shí)間為5秒的定時(shí)任務(wù)A,在第1秒時(shí)開(kāi)始執(zhí)行,需要執(zhí)行10秒鐘。在第6秒時(shí),定時(shí)任務(wù)A還沒(méi)有結(jié)束,此時(shí)下一個(gè)周期的任務(wù)B已經(jīng)開(kāi)始等待執(zhí)行。如果此時(shí)線程池中沒(méi)有足夠的空閑線程,那么定時(shí)任務(wù)B就會(huì)被阻塞,無(wú)法執(zhí)行。

解決方案:

針對(duì)上述問(wèn)題,我們可以采用以下兩種方案來(lái)解決:

方案一:修改線程池大小

為了避免因?yàn)榫€程池中線程數(shù)量不足引起的問(wèn)題,我們可以對(duì)線程池進(jìn)行配置,提高線程池的大小,從而確保有足夠的空閑線程來(lái)處理定時(shí)任務(wù)。

例如,我們可以在application.properties或application.yml或者使用@EnableScheduling + @Configuration來(lái)配置線程池大?。?/p>

spring.task.scheduling.pool.size=20

2. 多個(gè)定時(shí)任務(wù)并發(fā)執(zhí)行可能導(dǎo)致資源競(jìng)爭(zhēng)

在某些情況下,我們可能需要編寫(xiě)多個(gè)定時(shí)任務(wù),這些定時(shí)任務(wù)可能涉及到共享資源,例如數(shù)據(jù)庫(kù)連接、緩存對(duì)象等。當(dāng)多個(gè)定時(shí)任務(wù)同時(shí)執(zhí)行時(shí),就會(huì)存在資源競(jìng)爭(zhēng)的問(wèn)題,可能會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)誤或者系統(tǒng)崩潰。

解決方案:

為了避免由于多個(gè)定時(shí)任務(wù)并發(fā)執(zhí)行導(dǎo)致的資源競(jìng)爭(zhēng)問(wèn)題,我們可以采用以下兩種方案來(lái)解決:

方案一:使用鎖機(jī)制

鎖機(jī)制是一種常見(jiàn)的解決多線程并發(fā)訪問(wèn)共享資源的方式。在Java中,我們可以使用synchronized關(guān)鍵字或者Lock接口來(lái)實(shí)現(xiàn)鎖機(jī)制。

例如,下面是一個(gè)使用synchronized關(guān)鍵字實(shí)現(xiàn)鎖機(jī)制的示例:

private static Object lockObj = new Object();

@Scheduled(fixedDelay = 1000)
public void doSomething(){
    synchronized(lockObj){
        // 定時(shí)任務(wù)要執(zhí)行的內(nèi)容
    }
}

在上述代碼中,我們定義了一個(gè)靜態(tài)對(duì)象lockObj,用來(lái)保護(hù)共享資源。在定時(shí)任務(wù)執(zhí)行時(shí),我們使用synchronized關(guān)鍵字對(duì)lockObj進(jìn)行加鎖,從而確保多個(gè)定時(shí)任務(wù)不能同時(shí)訪問(wèn)共享資源。

方案二:使用分布式鎖

除了使用傳統(tǒng)的鎖機(jī)制外,還可以使用分布式鎖來(lái)解決資源競(jìng)爭(zhēng)問(wèn)題。分布式鎖是一種基于分布式系統(tǒng)的鎖機(jī)制,它可以不依賴(lài)于單個(gè)JVM實(shí)例,從而能夠保證多個(gè)定時(shí)任務(wù)之間的資源訪問(wèn)不會(huì)沖突。

在Java開(kāi)發(fā)中,我們可以使用ZooKeeper、Redis等分布式系統(tǒng)來(lái)實(shí)現(xiàn)分布式鎖機(jī)制。例如,使用Redis實(shí)現(xiàn)分布式鎖的示例代碼如下:

@Autowired
private RedisTemplate redisTemplate;

@Scheduled(fixedDelay = 1000)
public void doSomething(){
    String lockKey = "lock:key";
    String value = UUID.randomUUID().toString();
    Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, value, 5L, TimeUnit.SECONDS);
    if(result){
        try{
            // 定時(shí)任務(wù)要執(zhí)行的內(nèi)容
        }finally{
            redisTemplate.delete(lockKey);
        }
    }
}

在上述代碼中,我們使用Redis實(shí)現(xiàn)了分布式鎖機(jī)制。具體而言,我們?cè)诙〞r(shí)任務(wù)執(zhí)行時(shí),首先向Redis中寫(xiě)入一個(gè)鍵值對(duì),然后檢查是否成功寫(xiě)入。如果成功寫(xiě)入,則表示當(dāng)前定時(shí)任務(wù)獲得了鎖,可以執(zhí)行接下來(lái)的操作。在定時(shí)任務(wù)執(zhí)行完畢后,我們?cè)購(gòu)腞edis中刪除該鍵值對(duì),釋放鎖資源。

六、總結(jié)

通過(guò)以上的分析,我們可以了解到:雖然@Scheduled注解能夠非常方便地實(shí)現(xiàn)定時(shí)任務(wù)的功能,但是它也存在一些多線程的問(wèn)題。為此,需要注意到這些問(wèn)題,并采取相應(yīng)的措施來(lái)避免它們的出現(xiàn)。在實(shí)際開(kāi)發(fā)中,可以結(jié)合使用線程池、異步線程池、鎖機(jī)制、分布式鎖等方式,達(dá)到最佳的效果。

到此這篇關(guān)于SpringBoot中定時(shí)任務(wù)@Scheduled的多線程使用詳解的文章就介紹到這了,更多相關(guān)SpringBoot定時(shí)任務(wù)@Scheduled內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 20個(gè)非常實(shí)用的Java程序代碼片段

    20個(gè)非常實(shí)用的Java程序代碼片段

    這篇文章主要為大家分享了20個(gè)非常實(shí)用的Java程序片段,對(duì)java開(kāi)發(fā)項(xiàng)目有所幫助,感興趣的小伙伴們可以參考一下
    2016-02-02
  • 并行Stream與Spring事務(wù)相遇會(huì)發(fā)生什么?

    并行Stream與Spring事務(wù)相遇會(huì)發(fā)生什么?

    這篇文章主要介紹了并行Stream與Spring事務(wù)相遇會(huì)發(fā)生什么?文章主要解決實(shí)戰(zhàn)中的Bug及解決方案和技術(shù)延伸,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • 利用Spring Boot如何開(kāi)發(fā)REST服務(wù)詳解

    利用Spring Boot如何開(kāi)發(fā)REST服務(wù)詳解

    這篇文章主要給大家介紹了關(guān)于利用Spring Boot如何開(kāi)發(fā)REST服務(wù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • 從內(nèi)存方面解釋Java中String與StringBuilder的性能差異

    從內(nèi)存方面解釋Java中String與StringBuilder的性能差異

    我們通常會(huì)發(fā)現(xiàn)使用StringBuffer或StringBuilder創(chuàng)建出來(lái)的字符串在拼接時(shí)回避String要來(lái)得快,尤其是StringBuilder,本文就從內(nèi)存方面解釋Java中String與StringBuilder的性能差異,需要的朋友可以參考下
    2016-05-05
  • 基于Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié)

    基于Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié)

    這篇文章主要介紹了Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java中StringBuilder字符串類(lèi)型的操作方法及API整理

    Java中StringBuilder字符串類(lèi)型的操作方法及API整理

    Java中的StringBuffer類(lèi)繼承于AbstractStringBuilder,用來(lái)創(chuàng)建非線程安全的字符串類(lèi)型對(duì)象,下面即是對(duì)Java中StringBuilder字符串類(lèi)型的操作方法及API整理
    2016-05-05
  • JavaSE API實(shí)現(xiàn)生成隨機(jī)數(shù)的2種方法(Random類(lèi)和Math類(lèi)的Random方法)

    JavaSE API實(shí)現(xiàn)生成隨機(jī)數(shù)的2種方法(Random類(lèi)和Math類(lèi)的Random方法)

    本文主要介紹了JavaSE API實(shí)現(xiàn)生成隨機(jī)數(shù)的2種方法,主要包括Random類(lèi)和Math類(lèi)的random方法都可以用來(lái)生成隨機(jī)數(shù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • Spring零基礎(chǔ)入門(mén)IOC

    Spring零基礎(chǔ)入門(mén)IOC

    IoC就是比方說(shuō)有一個(gè)類(lèi),我們想要調(diào)用類(lèi)里面的方法(不是靜態(tài)方法),就要?jiǎng)?chuàng)建該類(lèi)的對(duì)象,使用對(duì)象調(diào)用方法來(lái)實(shí)現(xiàn)。但對(duì)于Spring來(lái)說(shuō),Spring創(chuàng)建對(duì)象的過(guò)程,不是在代碼里面實(shí)現(xiàn)的,而是交給Spring來(lái)進(jìn)行配置實(shí)現(xiàn)的
    2022-08-08
  • InputStreamReader 和FileReader的區(qū)別及InputStream和Reader的區(qū)別

    InputStreamReader 和FileReader的區(qū)別及InputStream和Reader的區(qū)別

    這篇文章主要介紹了InputStreamReader 和FileReader的區(qū)別及InputStream和Reader的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • Java入門(mén)絆腳石之Override和Overload的區(qū)別詳解

    Java入門(mén)絆腳石之Override和Overload的區(qū)別詳解

    重寫(xiě)是子類(lèi)對(duì)父類(lèi)的允許訪問(wèn)的方法的實(shí)現(xiàn)過(guò)程進(jìn)行重新編寫(xiě), 返回值和形參都不能改變。即外殼不變,核心重寫(xiě)!重寫(xiě)的好處在于子類(lèi)可以根據(jù)需要,定義特定于自己的行為。重載是在一個(gè)類(lèi)里面,方法名字相同,而參數(shù)不同。返回類(lèi)型可以相同也可以不同
    2021-10-10

最新評(píng)論

六安市| 泰州市| 新乡县| 林甸县| 博白县| 崇左市| 临漳县| 屯留县| 扶余县| 巴林左旗| 吴川市| 县级市| 张掖市| 民乐县| 新兴县| 遂川县| 临西县| 漯河市| 深水埗区| 融水| 县级市| 安宁市| 大冶市| 突泉县| 竹溪县| 巴里| 成都市| 内江市| 阿尔山市| 庆阳市| 嵊泗县| 尉犁县| 齐河县| 汾西县| 新建县| 罗平县| 庆安县| 枣强县| 普兰店市| 井研县| 浪卡子县|