溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

java中@Async異步調(diào)用的方法

發(fā)布時(shí)間:2022-07-14 10:21:25 來(lái)源:億速云 閱讀:482 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“java中@Async異步調(diào)用的方法”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“java中@Async異步調(diào)用的方法”吧!

    前言

    異步調(diào)用與同步調(diào)用

    • 同步調(diào)用:順序執(zhí)行,通過(guò)調(diào)用返回結(jié)果再次執(zhí)行下一個(gè)調(diào)用

    • 異步調(diào)用:通過(guò)調(diào)用,無(wú)需等待返回結(jié)果,執(zhí)行下一個(gè)調(diào)用

    1. @Async講解

    其@Async的注解代碼如下:

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Async {
        String value() default "";
    }

    注解可以使用在類(lèi)型以及方法中
    通過(guò)value定義其值,默認(rèn)是空

    一般這個(gè)注解需要配合@EnableAsync,起源碼如下

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({AsyncConfigurationSelector.class})
    public @interface EnableAsync {
        Class<? extends Annotation> annotation() default Annotation.class;
    
        boolean proxyTargetClass() default false;
    
        AdviceMode mode() default AdviceMode.PROXY;
    
        int order() default Integer.MAX_VALUE;
    }

    主要通過(guò)該注解放置在啟動(dòng)類(lèi)中進(jìn)行配置啟動(dòng)

    在啟動(dòng)類(lèi)中添加如下:

    @SpringbootApplication
    @EnableAsync
    public class Application{
        public static void main(String[] args){
            SrpingApplication.run(Application.class, args);
        }
    }

    2. 用法

    2.1 同步調(diào)用

    從調(diào)用到返回函數(shù)結(jié)果才能執(zhí)行下一步,稱(chēng)為同步調(diào)用

    service層 代碼:

    public class Service{
        public void test01() throws InterruptedException{
            Thread.sleep(5000);
            System.out.println("保存日志");
        }
    }

    控制層代碼模塊:

    public class Controler{
        @Autowired
        private Service service;
    
        @GetMapping("/test")
        public String getTest(){
            try{
                System.out.println("開(kāi)始");
                service.test01();
                System.out.println("結(jié)束");            
            }catch(InterruptedException e){
                e.prinStackTrace();
            }
        }
        
    }

    通過(guò)springboot的啟動(dòng)類(lèi)啟動(dòng)之后

    輸出如下:

    開(kāi)始

    // 此為等待5秒鐘,終端不顯示也不關(guān)閉

    結(jié)束

    2.2 異步調(diào)用

    異步調(diào)用,執(zhí)行函數(shù)不用等返回結(jié)果就可以執(zhí)行下一步

    service層 代碼:
    主要是添加了@Async注解標(biāo)識(shí)這個(gè)方法

    public class Service{
        @Async
        public void test01() throws InterruptedException{
            Thread.sleep(500);
            System.out.println("保存日志");
        }
    }

    控制層代碼模塊:

    通過(guò)調(diào)用service層函數(shù)

    public class Controler{
        @Autowired
        private Service service;
    
        @GetMapping("/test")
        public String getTest(){
            try{
                System.out.println("開(kāi)始");
                service.test01();
                System.out.println("結(jié)束");            
            }catch(InterruptedException e){
                e.prinStackTrace();
            }
        }
        
    }

    以及在啟動(dòng)類(lèi)中加入注解啟動(dòng) @EnableAsync

    @SpringbootApplication
    @EnableAsync
    public class Application{
        public static void main(String[] args){
            SrpingApplication.run(Application.class, args);
        }
    }

    3. 自定義線(xiàn)程池

    對(duì)于線(xiàn)程池的一些基本知識(shí)可看我之前的文章:

    java如何正確關(guān)閉線(xiàn)程以及線(xiàn)程池(代碼實(shí)踐含源碼分析)
    java線(xiàn)程池的創(chuàng)建方式詳細(xì)分析(全)

    如果不指定線(xiàn)程池,默認(rèn)使用的線(xiàn)程池為SimpleAsyncTaskExecutor(來(lái)一個(gè)任務(wù)就創(chuàng)建一個(gè)線(xiàn)程,不斷創(chuàng)建線(xiàn)程導(dǎo)致CPU過(guò)高引發(fā)OOM),自帶的線(xiàn)程池一般都有弊端,一般推薦使用ThreadPoolExecutor(明確線(xiàn)程池的資源,規(guī)避風(fēng)險(xiǎn))

    具體如下:

    • newFixedThreadPool:定死了線(xiàn)程數(shù),任務(wù)隊(duì)列還是無(wú)界的,(最大線(xiàn)程數(shù)只有隊(duì)列滿(mǎn)了,最大線(xiàn)程數(shù)才會(huì)創(chuàng)建),所以會(huì)造成OOM

    • newCachedThreadPool:沒(méi)有設(shè)置最大線(xiàn)程數(shù)上限,創(chuàng)建大量的線(xiàn)程容易卡頓或者直接OOM

    通過(guò)自定義線(xiàn)程池可以調(diào)整線(xiàn)程池的配置,更好的資源利用

    @Async這個(gè)注解查找 AsyncConfigurer接口(實(shí)現(xiàn)類(lèi)為AsyncConfigurerSupport,默認(rèn)配置和方法都是空),所以可重寫(xiě)接口指定線(xiàn)程池。

    • 通過(guò)實(shí)現(xiàn)接口AsyncConfigurer

    • 繼承AsyncConfigurerSupport

    • 自定義TaskExecutor(替代內(nèi)置任務(wù)執(zhí)行器)

    第三種方法:

    在application.xml中定義線(xiàn)程池的一些變量

    thread.core.size=16
    thread.max.size=16
    thread.queue.size=30
    
    thread.prefix=xx-

    自定義線(xiàn)程池如下

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.ThreadPoolExecutor;
    
    @Configuration
    public class ThreadPoolConfig {
        // 線(xiàn)程名稱(chēng)前綴
        @Value("${thread.prefix}")
        private String threadPrefix;
        
        // 核心線(xiàn)程數(shù)
        @Value("${thread.core.size}")
        private int coreSize;
    
        // 最大線(xiàn)程數(shù)
        @Value("${thread.max.size}")
        private int maxSize;
        
        // 隊(duì)列長(zhǎng)度
        @Value("${thread.queue.size}")
        private int queueSize;
        
        // 通過(guò)bean注解注入
        @Bean("xx")
        public ThreadPoolTaskExecutor taskExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            //設(shè)置線(xiàn)程池參數(shù)信息
            taskExecutor.setCorePoolSize(coreSize);
            taskExecutor.setMaxPoolSize(maxSize);
            taskExecutor.setQueueCapacity(queueSize);
            taskExecutor.setThreadNamePrefix(threadPrefix);
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            taskExecutor.setAwaitTerminationSeconds(30);
            
            //修改拒絕策略為使用當(dāng)前線(xiàn)程執(zhí)行
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            
            //初始化線(xiàn)程池
            taskExecutor.initialize();
            return taskExecutor;
        }
    }

    到此,相信大家對(duì)“java中@Async異步調(diào)用的方法”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI