springboot2.x | @Async實(shí)現(xiàn)異步和線程池的使

簡(jiǎn)介

大部分的情況我們的代碼的執(zhí)行都是按照代碼的調(diào)用順序來(lái)從頭執(zhí)行到尾。打印出線程的名字是http-nio-8080-exec-x 某個(gè)線程。在我們執(zhí)行異步任務(wù)的時(shí)候需要?jiǎng)?chuàng)建線程池來(lái)處理異步任務(wù)。

修改啟動(dòng)main

@SpringBootApplication
@EnableAsync
@EnableScheduling
public class StudySpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudySpringbootApplication.class, args);
    }
}

創(chuàng)建線程池

線程池雖好但也要做好隔離。如果所有的業(yè)務(wù)都應(yīng)用一個(gè)線程池,當(dāng)其中的一個(gè)業(yè)務(wù)把線程池占滿,就會(huì)影響其他的業(yè)務(wù)正常的運(yùn)作。我們可以設(shè)置幾個(gè)線程池來(lái)定制化為需要的業(yè)務(wù)。列如: pool1 為異步任務(wù), pool2 為定時(shí)任務(wù)防止定時(shí)任務(wù)沖突導(dǎo)致任務(wù)的丟棄。

@Configuration
public class PoolConfig {

    @Bean(name = "pool1")
    public ThreadPoolTaskExecutor taskExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 設(shè)置核心線程數(shù)
        executor.setCorePoolSize(5);
        // 設(shè)置最大線程數(shù)
        executor.setMaxPoolSize(10);
        // 設(shè)置隊(duì)列容量
        executor.setQueueCapacity(20);
        // 設(shè)置線程活躍時(shí)間(秒)
        executor.setKeepAliveSeconds(60);
        // 設(shè)置默認(rèn)線程名稱
        executor.setThreadNamePrefix("wh1-");
        // 設(shè)置拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務(wù)結(jié)束后再關(guān)閉線程池
        executor.setWaitForTasksToCompleteOnShutdown(true);

        return executor;
    }

    @Bean(name = "pool2")
    public ThreadPoolTaskExecutor taskExecutor2() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 設(shè)置核心線程數(shù)
        executor.setCorePoolSize(2);
        // 設(shè)置最大線程數(shù)
        executor.setMaxPoolSize(4);
        // 設(shè)置隊(duì)列容量
        executor.setQueueCapacity(20);
        // 設(shè)置線程活躍時(shí)間(秒)
        executor.setKeepAliveSeconds(60);
        // 設(shè)置默認(rèn)線程名稱
        executor.setThreadNamePrefix("wh2-");
        // 設(shè)置拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務(wù)結(jié)束后再關(guān)閉線程池
        executor.setWaitForTasksToCompleteOnShutdown(true);

        return executor;
    }

}

建異步服務(wù)

@Service
public class TaskAsyncService {

    /**
     * 無(wú)返回值
     * @throws Exception
     */
    @Async(value = "pool1")
    public void taskOne() throws Exception {

        Thread.sleep(4000);
        System.out.println("task one " + Thread.currentThread().getName());
    }

    /**
     * 無(wú)返回值
     * @throws Exception
     */
    @Async(value = "pool1")
    public void taskTwo() throws Exception {

        System.out.println("task two " + Thread.currentThread().getName());
    }

    /**
     * 有返回值回調(diào)的異步任務(wù)
     * @return
     * @throws Exception
     */
    @Async(value = "pool1")
    public Future<String> taskOne2() throws Exception {

        Thread.sleep(4000);
        System.out.println("task one " + Thread.currentThread().getName());

        return new AsyncResult<>("task one done");
    }

    /**
     * 有返回值回調(diào)的異步任務(wù)
     * @return
     * @throws Exception
     */
    @Async(value = "pool1")
    public Future<String> taskTwo2() throws Exception {

        System.out.println("task two " + Thread.currentThread().getName());

        return new AsyncResult<>("task two done");
    }
}

創(chuàng)建action

    @GetMapping("/async-test")
    public Response taskTest() throws Exception {
        /**
         * 1.執(zhí)行http 請(qǐng)求任務(wù)的線程是 http-nio-8080-exec ,
         * 2.執(zhí)行 異步任務(wù)的線程是自定義線程池中的某個(gè)線程
         * 3.如果定時(shí)任務(wù)中的線程默認(rèn)是開(kāi)啟一個(gè)線程,可以通過(guò) @Async 指定線程池中的某個(gè)線程
         */
        System.out.println("taskTest thread name : " + Thread.currentThread().getName());

        //無(wú)返回值
        //asyncService.taskOne();
        //asyncService.taskTwo();

        Future<String> future1 = asyncService.taskOne2();
        Future<String> future2 = asyncService.taskTwo2();

        while (true){
            if(future1.isDone() && future2.isDone()){
                System.out.println("異步調(diào)用完成 : " + future1.get() + future2.get());
                break;
            }
        }
        //調(diào)用同步函數(shù)
        this.test1();

        return new Response(0, "success");
    }

    public void test1(){
        System.out.println("function test1 : " + Thread.currentThread().getName());
    }

定時(shí)任務(wù)

@Service
public class ScheduleTask {

    @Async(value = "pool2")
    @Scheduled(fixedRate = 5000)
    public void task1(){
        /**猜測(cè)是維持一個(gè)線程 來(lái)處理定時(shí)任務(wù),如果多個(gè)定時(shí)任務(wù)沖突,這個(gè)線程會(huì)丟棄掉這個(gè)任務(wù)*/
        System.out.println("schedele task1 :" + Thread.currentThread().getName());
    }

}

打印日志

## 方法執(zhí)行
taskTest thread name : http-nio-8080-exec-1
task two wh1-2
task one wh1-1
異步調(diào)用完成 : task one donetask two done
function test1 : http-nio-8080-exec-1
##定時(shí)任務(wù)
schedele task1 :wh2-2
schedele task1 :wh2-1

線程池:
https://juejin.cn/post/6844903834158907399#heading-0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容