SpringBootスレッドプールの使用

113871 ワード

SpringBootスレッドプールの使用
ソフトウェア環境
名前
バージョン番号
jdk
1.8
springboot
2.1.6
maven
3.3.9
1.Javaでスレッドプールを作成する
JavaミッドレンジプールのコアクラスThreadPoolExecutorのみを紹介します.その他の使い方はご自身でお問い合わせください
1.1 ThreadPoolExecutorクラスの紹介
jdk 1.8ソースコード一部削除
 package java.util.concurrent;
    /**
     * @param corePoolSize       ->            ,             ,
     *             {@code allowCoreThreadTimeOut}        
     * @param maximumPoolSize       ->                
     *                            ,   OOM(OutOfMemoryError)  
     * @param keepAliveTime        ->                ,
     *                             ,             .
     * @param unit {@code keepAliveTime}         .eg:TimeUnit.SECONDS
     * @param workQueue      ->                      .
     * @param threadFactory      ->                          .
     *        (   ThreadFactory                  ,           、
     *                 ,                 .
     *          ,   ThreadFactory                    。)
     * @param handler                        ,                handler,
     *                   (           ThreadPoolExecutor  execute     )
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    }

ThreadPoolExecutorの実行プロセスは次のとおりです.
新しいタスクの送信
YES
NO
YES
NO
YES
NO
プライマリスレッド
スレッドプール
スレッド数
新規スレッド処理要求
ワークキューがいっぱいかどうか
スレッド数
新しいタスクをキューに配置
新規スレッド処理要求
RejectedExecutionHandlerを呼び出して拒否処理を行います
1.            
2.                       ,           ;                .
3.                     ;                        .
4.                           ;     RejectedExecutionHandler      .

jdkデフォルトでは、4つのRejectedExecutionHandlerインタフェースの実装が提供されています.
  • AbortPolicy:RejectedExecutionException異常
  • を直接投げ出す
  • CallerRunsPolicy:メインスレッドに渡す
  • DiscardOldestPolicy:ワークキュー内の古いタスクを捨てて、新しいタスクをキューに追加します.廃棄されたタスクが再び実行できなくなる
  • .
  • DiscardPolicy:現在のタスクを放棄する;放棄されたタスクが再び実行できなくなる
  • もちろん、RejectedExecutionHandlerインタフェースを実装するだけで拒否ポリシーをカスタマイズすることもできます.
    2.Springでスレッドプールを作成する
    2.1 ThreadPoolTaskExecutorクラスの紹介
        package org.springframework.scheduling.concurrent;
    
        public class ThreadPoolTaskExecutor {
            private final Object poolSizeMonitor = new Object(); //       ,                
            private int corePoolSize = 1; //      
            private int maxPoolSize = 2147483647; //      
            private int keepAliveSeconds = 60; //       
            private int queueCapacity = 2147483647; //       
            private boolean allowCoreThreadTimeOut = false; //           ,false   
            private TaskDecorator taskDecorator; //                 ,             /  
            private ThreadPoolExecutor threadPoolExecutor; // java        

    ソースコードからThreadPoolTaskExecutorはjavaのThreadPoolExecutorに基づいてカプセル化されていることがわかります
    3.スレッドプール使用例
    3.1 ThreadPoolTaskExecutorの使用
  • pomファイル
  •         <!--     springboot-web       -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--     springboot-test         -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
  • configクラス
  • SpringBootの構成クラスでスレッドプールのBeanと対応するパラメータを構成する必要があります.
    import java.util.concurrent.Executor;
    import java.util.concurrent.ThreadPoolExecutor;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    @Configuration
    @EnableAsync //         
    public class ThreadPoolConfig {
    
        @Bean
        public Executor threadPoolTaskExecutor() {
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
            //        
            threadPoolTaskExecutor.setCorePoolSize(5);
            //        
            threadPoolTaskExecutor.setMaxPoolSize(5);
            //         
            threadPoolTaskExecutor.setQueueCapacity(2000);
            //         
            threadPoolTaskExecutor.setThreadNamePrefix("threadPoolTaskExecutor-->");
            //       .       ,            ,       RejectedExecutionException  
            threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
            //       
            threadPoolTaskExecutor.initialize();
            return threadPoolTaskExecutor;
        }
    }
    
  • 呼び出しメソッドService
  • import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class HelloService {
    
        Logger logger = LoggerFactory.getLogger(HelloService.class);
        
         /**
         * @Async     ,       ;           ,
         *             ,           ,         。
         */
        @Async //       
        public void sayHello() {
            logger.info("start say hello");
            System.out.println(Thread.currentThread().getName());
            System.out.println("hello");
            logger.info("end say hello");
        }
    }
    
  • テストクラス
  • import com.cain.threadpool.ThreadPoolApplication;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = ThreadPoolApplication.class)
    public class HelloServiceTest {
    
        @Autowired
        HelloService helloService;
    
        @Test
        public void testSayHello() throws Exception {
            helloService.sayHello();
        }
    } 
    
  • 試験結果
  • 2019-07-02 18:36:25.138  INFO 2868 --- [           main] t.c.e.demo.service.HelloServiceTest      : Starting HelloServiceTest on DLC00R90RK7NBL with PID 2868 (started by jiaxin.chi in C:\Users\jiaxin.chi\Desktop\demo)
    2019-07-02 18:36:25.140  INFO 2868 --- [           main] t.c.e.demo.service.HelloServiceTest      : No active profile set, falling back to default profiles: default
    2019-07-02 18:36:26.892  INFO 2868 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService
    2019-07-02 18:36:26.913  INFO 2868 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'threadPoolTaskExecutor'
    2019-07-02 18:36:28.644  INFO 2868 --- [           main] t.c.e.demo.service.HelloServiceTest      : Started HelloServiceTest in 3.98 seconds (JVM running for 6.103)
    2019-07-02 18:36:29.047  INFO 2868 --- [askExecutor-->1] com.example.demo.service.HelloService    : start say hello
    threadPoolTaskExecutor-->1
    hello
    2019-07-02 18:36:29.048  INFO 2868 --- [askExecutor-->1] com.example.demo.service.HelloService    : end say hello
    2019-07-02 18:36:29.051  INFO 2868 --- [       Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'threadPoolTaskExecutor'
    

    テストの結果からsayHelloメソッドが我々が定義したスレッドプール内のスレッドによって実行されていることが明らかになった.
    名前の長さの制限が表示されているため、askExecutor->1が表示されますが、現在のスレッドの名前をメソッドに印刷することで、私たちが設定したスレッドthreadPoolTaskExecutorであることがわかります.>1
    3.2 ThreadPoolExecutorの使用
  • configクラスに以下の構成
  • を追加する.
        @Bean
        public Executor myThreadPool() {
            //        
            int corePoolSize = 5;
            //        
            int maxPoolSize = 5;
            //         
            int queueCapacity = 2000;
            //       
            long keepAliveTime = 30;
            //         
            String threadNamePrefix = "myThreadPool-->";
            //          .       ,            ,       RejectedExecutionException  
            RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    throw new RejectedExecutionException("    RejectedExecutionHandler");
                }
            };
            //        
            ThreadFactory threadFactory = new ThreadFactory() {
                private int i = 1;
    
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setName(threadNamePrefix + i);
                    i++;
                    return thread;
                }
            };
            //       
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize,
                    keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<>(queueCapacity),
                    threadFactory, rejectedExecutionHandler);
            return threadPoolExecutor;
        }
    

    configクラスに2つのスレッドプールが構成されていることがわかります.いずれかのスレッドプールを使用するには、次の方法を指定します.
    どのスレッドプールを使用するかが指定されていない場合は、ThreadPoolTaskExecutorが優先されます.
        @Async("myThreadPool") //                  bean id ①
        public void sayHello() {
            logger.info("start say hello");
            System.out.println(Thread.currentThread().getName());
            System.out.println("hello");
            logger.info("end say hello");
        }
    
  • 試験結果
  • 2019-07-03 10:26:55.515  INFO 13304 --- [           main] t.c.e.demo.service.HelloServiceTest      : Starting HelloServiceTest on DLC00R90RK7NBL with PID 13304 (started by jiaxin.chi in C:\Users\jiaxin.chi\Desktop\demo)
    2019-07-03 10:26:55.517  INFO 13304 --- [           main] t.c.e.demo.service.HelloServiceTest      : No active profile set, falling back to default profiles: default
    2019-07-03 10:26:56.768  INFO 13304 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService
    2019-07-03 10:26:56.789  INFO 13304 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'threadPoolTaskExecutor'
    2019-07-03 10:26:57.997  INFO 13304 --- [           main] t.c.e.demo.service.HelloServiceTest      : Started HelloServiceTest in 2.824 seconds (JVM running for 4.462)
    2019-07-03 10:26:58.258  INFO 13304 --- [yThreadPool-->1] com.example.demo.service.HelloService    : start say hello
    myThreadPool-->1
    hello
    2019-07-03 10:26:58.258  INFO 13304 --- [yThreadPool-->1] com.example.demo.service.HelloService    : end say hello
    2019-07-03 10:26:58.260  INFO 13304 --- [       Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'threadPoolTaskExecutor'
    

    3.3カスタムThreadPoolTaskExecutor
  • MyThreadPoolTaskExecutor
  • を作成
    import java.util.concurrent.Callable;
    import java.util.concurrent.Future;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    import org.springframework.util.concurrent.ListenableFuture;
    
    public class MyThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
    
        Logger logger = LoggerFactory.getLogger(MyThreadPoolTaskExecutor.class);
    
        @Override
        public void execute(Runnable task) {
            logThreadPoolStatus();
            super.execute(task);
        }
    
        @Override
        public void execute(Runnable task, long startTimeout) {
            logThreadPoolStatus();
            super.execute(task, startTimeout);
        }
    
        @Override
        public Future<?> submit(Runnable task) {
            logThreadPoolStatus();
            return super.submit(task);
        }
    
        @Override
        public <T> Future<T> submit(Callable<T> task) {
            logThreadPoolStatus();
            return super.submit(task);
        }
    
        @Override
        public ListenableFuture<?> submitListenable(Runnable task) {
            logThreadPoolStatus();
            return super.submitListenable(task);
        }
    
        @Override
        public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
            logThreadPoolStatus();
            return super.submitListenable(task);
        }
        
        /**
         *                    
         */
        private void logThreadPoolStatus() {
            logger.info("     :{},      :{},      : {},       : {}",
            getCorePoolSize(), getMaxPoolSize(), getPoolSize(), getActiveCount());
        }
    }
    
    

    カスタムThreadPoolTaskExecutorでは、上記のパラメータを含むスレッドプールの現在の状態を出力することができます.
  • configクラスに構成
  • を追加
        @Bean
        public Executor myThreadPoolTaskExecutor() {
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new MyThreadPoolTaskExecutor();
            //        
            threadPoolTaskExecutor.setCorePoolSize(5);
            //        
            threadPoolTaskExecutor.setMaxPoolSize(5);
            //         
            threadPoolTaskExecutor.setQueueCapacity(2000);
            //         
            threadPoolTaskExecutor.setThreadNamePrefix("myThreadPoolTaskExecutor-->");
            //       .       ,            ,       RejectedExecutionException  
            threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
            //       
            threadPoolTaskExecutor.initialize();
            return threadPoolTaskExecutor;
        }
    

    ThreadPoolTaskExecutorのインスタンス化されたオブジェクトをカスタムに置き換えるだけでよい
    3.4@Async戻り値に基づく呼び出し
    以上の例では、@Asyncの戻り値のない呼び出しに基づいています.次に、戻り値のある呼び出しについて説明します.
  • エンティティオブジェクト
  • を追加
    public class HelloEntity {
        private String helloStr;
    
        public String getHelloStr() {
            return helloStr;
        }
    
        public void setHelloStr(String helloStr) {
            this.helloStr = helloStr;
        }
    }
    
  • は、サービスにおいて、以下の方法
  • を追加する.
        @Async
        public Future<HelloEntity> getHelloString() {
            logger.info("start getHelloString");
            HelloEntity helloEntity = new HelloEntity();
            helloEntity.setHelloStr("Say hello to little wang");
            System.out.println(Thread.currentThread().getName());
            logger.info("end getHelloString");
            return new AsyncResult<>(helloEntity);
        }
    

    Futureの使い方に慣れていない場合は、jdkのJUCパッケージを学ぶことをお勧めします
    AsyncResultはspringパッケージと@Asyncを組み合わせて使用した非同期戻り結果です
     Tips:     :       ,       ,             。
               ,        AsyncTaskExecutor。
       AsyncResult   
     [As of Spring 4.2, this class also supports passing execution exceptions back to the caller.]
         Spring4.2           ,                      .
                     spring          .
                        ,        .
    
  • テストクラス
  •     @Test
        public void testGetHelloString() throws Exception {
            Future<HelloEntity> helloString = helloService.getHelloString();
            HelloEntity helloEntity = helloString.get();
            System.out.println(helloEntity.getHelloStr());
        }
    
  • 試験結果
  • 2019-07-03 11:01:11.603  INFO 13492 --- [           main] t.c.e.demo.service.HelloServiceTest      : Starting HelloServiceTest on DLC00R90RK7NBL with PID 13492 (started by jiaxin.chi in C:\Users\jiaxin.chi\Desktop\demo)
    2019-07-03 11:01:11.604  INFO 13492 --- [           main] t.c.e.demo.service.HelloServiceTest      : No active profile set, falling back to default profiles: default
    2019-07-03 11:01:13.205  INFO 13492 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService
    2019-07-03 11:01:13.226  INFO 13492 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'threadPoolTaskExecutor'
    2019-07-03 11:01:14.729  INFO 13492 --- [           main] t.c.e.demo.service.HelloServiceTest      : Started HelloServiceTest in 3.613 seconds (JVM running for 5.579)
    2019-07-03 11:01:15.070  INFO 13492 --- [askExecutor-->1] com.example.demo.service.HelloService    : start getHelloString
    threadPoolTaskExecutor-->1
    2019-07-03 11:01:15.071  INFO 13492 --- [askExecutor-->1] com.example.demo.service.HelloService    : end getHelloString
    Say hello to little wang
    2019-07-03 11:01:15.087  INFO 13492 --- [       Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'threadPoolTaskExecutor'
    

    3.5デフォルト構成のスレッドプールの使用
    configクラスを構成する必要はありません.起動クラスに次の注釈を付けるだけです.
  • ThreadPoolApplication
  • import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @SpringBootApplication
    @EnableAsync //         
    public class ThreadPoolApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ThreadPoolApplication.class, args);
        }
    
    }
    
  • service
  •     @Async
        public void sayHello() {
            logger.info("start say hello");
            System.out.println(Thread.currentThread().getName());
            System.out.println("hello");
            logger.info("end say hello");
        }
    
  • 試験方法
  •     @Test
        public void testSayHello() throws Exception {
            helloService.sayHello();
        }
    
  • 試験結果
  • 2019-07-04 17:26:57.406  INFO 20620 --- [           main] c.c.threadpool.service.HelloServiceTest  : Starting HelloServiceTest on DLC00R90RK7NBL with PID 20620 (started by jiaxin.chi in E:\threadpooltest)
    2019-07-04 17:26:57.407  INFO 20620 --- [           main] c.c.threadpool.service.HelloServiceTest  : No active profile set, falling back to default profiles: default
    2019-07-04 17:26:59.757  INFO 20620 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2019-07-04 17:27:00.458  INFO 20620 --- [           main] c.c.threadpool.service.HelloServiceTest  : Started HelloServiceTest in 3.337 seconds (JVM running for 4.728)
    2019-07-04 17:27:00.880  INFO 20620 --- [         task-1] c.cain.threadpool.service.HelloService   : start say hello
    task-1
    hello
    2019-07-04 17:27:00.880  INFO 20620 --- [         task-1] c.cain.threadpool.service.HelloService   : end say hello
    2019-07-04 17:27:00.887  INFO 20620 --- [       Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
    Disconnected from the target VM, address: '127.0.0.1:49464', transport: 'socket'
    

    ログからデフォルトで使用されているのはThreadPoolTaskExecutorというクラスであることがわかります
    Tips:                ,                     
    

    4実戦デモ
    プロジェクトで使用したシーンを共有
    ログインと顔認識の2つのサービスがあります.
    ユーザーが登录する时、データベースに行ってユーザーのアカウントの状态を调べていくつか业务のロジックの判断をする必要があって、同时にオンラインの颜の识别を行う必要があります.2つの検査がすべて通る时やっと成功して登录することができます.この时私达は非同期の呼び出しのオンラインの颜の识别のインタフェースを使って、それによってシステムの応答の时间を速めることができます.
    4.1コードデモ
  • LoginService
  • import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;
    
    import com.cain.threadpool.entity.CainResult;
    import com.cain.threadpool.entity.FaceVerificationResult;
    import com.cain.threadpool.entity.UserInfo;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.AsyncResult;
    import org.springframework.stereotype.Service;
    
    @Service
    public class LoginService {
    
        Logger logger = LoggerFactory.getLogger(LoginService.class);
    
        @Autowired
        FaceVerifiationService faceVerifiationService;
    
        @Autowired
        ApplicationContext applicationContext;public CainResult login(UserInfo userInfo) {
            CainResult cainResult = new CainResult();
            LoginService loginService = applicationContext.getBean(LoginService.class);
            Future<FaceVerificationResult> onlineFaceVerificationResult = loginService.getOnlineFaceVerificationResult(userInfo);
            try {
                //                           
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            FaceVerificationResult faceVerificationResult = null;
            try {
                //   3              
                faceVerificationResult = onlineFaceVerificationResult.get(3, TimeUnit.SECONDS);
            } catch (Exception e) {
                logger.error("          ");
                //     
            }
            if (faceVerificationResult != null) {
                cainResult.setCode(faceVerificationResult.getCode());
                cainResult.setMessage(faceVerificationResult.getMessage());
            }
            return cainResult;
        }
    
        @Async
        public Future<FaceVerificationResult> getOnlineFaceVerificationResult(UserInfo userInfo) {
            logger.info("    ");
            FaceVerificationResult result = faceVerifiationService.getResult(userInfo);
            return new AsyncResult<>(result);
        }
    }
    
    
  • パッケージBean
  • public class CainResult {
        private Integer code;
        private String message;
    }
    
    public class FaceVerificationResult {
        private int code;
        private String message;
    }
    
    public class UserInfo {
        private Integer id;
        private String name;
        private String photo;
    }
    
  • FaceVerifiationService
  • package com.cain.threadpool.service;
    
    import com.cain.threadpool.entity.FaceVerificationResult;
    import com.cain.threadpool.entity.UserInfo;
    import org.springframework.stereotype.Service;
    
    @Service
    public class FaceVerifiationService {
    
        public FaceVerificationResult getResult(UserInfo userInfo) {
            FaceVerificationResult faceVerificationResult = new FaceVerificationResult();
            //      100
            faceVerificationResult.setCode(100);
            faceVerificationResult.setMessage("success");
            try {
                //            http       
                Thread.sleep(1000);
                //                    
                // 4(          ) + 3(       )    7s     
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return faceVerificationResult;
        }
    }
    
    

    コードの中でThread.sleep()で2つの方法をシミュレートした.1つはデータベースと業務論理処理を呼び出し,1つは顔認識を呼び出すインタフェースである.
    2つのメソッドが並列で、他の要因を考慮しない場合、loginメソッドの実行時間は5 s程度である.例では顔認識インタフェースを呼び出す方法を非同期で呼び出すので、最終的な実行時間は4 s程度であるべきである.
  • 試験方法
  • @RunWith(SpringRunner.class)
    @SpringBootTest(classes = ThreadPoolApplication.class)
    public class LoginServiceTest {
    
        @Autowired
        LoginService loginService;
    
        @Test
        public void login() {
            UserInfo userInfo = new UserInfo();
            long start = Instant.now().toEpochMilli();
            loginService.login(userInfo);
            long end = Instant.now().toEpochMilli();
            System.out.println(end - start);
        }
    }
    
  • 試験結果
  • 2019-07-04 18:51:36.968  INFO 28924 --- [           main] c.c.threadpool.service.LoginServiceTest  : Starting LoginServiceTest on DLC00R90RK7NBL with PID 28924 (started by jiaxin.chi in E:\threadpooltest)
    2019-07-04 18:51:36.970  INFO 28924 --- [           main] c.c.threadpool.service.LoginServiceTest  : No active profile set, falling back to default profiles: default
    2019-07-04 18:51:39.622  INFO 28924 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2019-07-04 18:51:40.143  INFO 28924 --- [           main] c.c.threadpool.service.LoginServiceTest  : Started LoginServiceTest in 3.728 seconds (JVM running for 6.121)
    2019-07-04 18:51:40.505  INFO 28924 --- [         task-1] c.cain.threadpool.service.LoginService   :     
    4018
    2019-07-04 18:51:44.514  INFO 28924 --- [       Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
    

    ログからスレッドプールが呼び出されていることがわかりました.メソッドは非同期で実行され、実行時間は4018ミリ秒、つまり4秒です.
    ソースアドレス:https://gitee.com/cjx940216/springboot-thread-pool-executor
  • 後記:
  • @Configuration
    public class ThreadPoolConfig {
    
        @Bean
        public HelloService helloService() {
            ...
        }
    
    }
    

    この構成はxmlでの以前の構成と同じです
    <beans>
        <bean id="helloService" class="com.cain.HelloServiceImpl"/>
    </beans>
    

    ②ここで使われているのは
     LoginService loginService = applicationContext.getBean(LoginService.class);
     loginService.getOnlineFaceVerificationResult(userInfo);
    

    できません
        this.getOnlineFaceVerificationResult(userInfo);
    

    Spring-aopはエージェントによってメソッドを強化するため(拡張メソッドの注釈は@Transactionalや@Asynなど)、ここでt h i s.bfcolor{purple}{this.}this.g e t O n l i n e F a c e V e r i f i f i c a t i o n e s u l tbfcolor{blue}{getOnlineFaceVerificationResult}getOnlineFaceVerificationResult(u s e r I n f o)\bf\color{black}{(userInfo)} (userInfo);エージェントではなく真実の方法を使用しているので、非同期操作は実行されません.つまりspring-aopの強化を迂回して、具体的な詳細は次の文章で説明します.