Overview

スレッド初期化のシーケンス図

Explanation

Tomcatのスレッドプールに直接タスクを依頼する方法がわかったため、前回の続きとして記載します。

処理フローは概要の「スレッド初期化のシーケンス図」の通りです。

以下、実際のプログラムを載せておきます。

1. ThreadInitializer2

  • main threadで実行されるプログラムは、onApplicationEventメソッド。
  • tomcat threadで実行されるプログラムは、threadInitメソッド。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@Slf4j
@Component
public class ThreadInitializer2 implements TomcatConnectorCustomizer, ApplicationListener<ContextRefreshedEvent> {

    private volatile Connector connector;

    @Value("${server.tomcat.max-threads:0}")
    private Integer threadNum;

    @Override
    public void customize(Connector connector) {
        this.connector = connector;
    }

    @SneakyThrows
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        this.connector.pause();
        this.connector.getProtocolHandler().start();

        // Tomcat のスレッドプールの取得
        Executor executor = this.connector.getProtocolHandler().getExecutor();

        // スレッドのタスク完了の待ち合わせ用リスト
        List<Future<?>> list = new ArrayList<>();

        if (executor instanceof ThreadPoolExecutor) {
            ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;

            // スレッド初期化タスクを依頼する
            IntStream.range(0, threadNum).forEach(i -> {
                Future<?> future = threadPoolExecutor.submit(this::threadInit);
                list.add(future);
            });

            // スレッド初期化タスクの完了を待つ
            for (Future<?> future : list) {
                try {
                    future.get();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void threadInit() {
        try {
            Thread.sleep(10000); // 初期化タスクに10秒かかるとする。
            log.info("do something for thread init.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

2. Execution result

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
14:49:58: Executing task 'ThreadInitOnDeploymentApplication.main()'...

> Task :compileJava
> Task :processResources UP-TO-DATE
> Task :classes

> Task :ThreadInitOnDeploymentApplication.main()

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.6.RELEASE)

2020-05-02 14:50:02.841  INFO 65733 --- [           main] c.e.t.ThreadInitOnDeploymentApplication  : Starting ThreadInitOnDeploymentApplication on MacBook-Air.local with PID 65733 (/Users/takuto-n/Documents/Basic_study/private_repo/ctrl-key-6bit-mask/java/thread-init-on-deployment/build/classes/java/main started by takuto-n in /Users/takuto-n/Documents/Basic_study/private_repo/ctrl-key-6bit-mask/java/thread-init-on-deployment)
2020-05-02 14:50:02.853  INFO 65733 --- [           main] c.e.t.ThreadInitOnDeploymentApplication  : No active profile set, falling back to default profiles: default
2020-05-02 14:50:04.779  INFO 65733 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-05-02 14:50:05.231  INFO 65733 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-05-02 14:50:05.231  INFO 65733 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-05-02 14:50:05.418  INFO 65733 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-05-02 14:50:05.418  INFO 65733 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2444 ms
2020-05-02 14:50:05.693  INFO 65733 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-05-02 14:50:15.962  INFO 65733 --- [io-8080-exec-10] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-7] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-9] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-4] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-6] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-1] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-8] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-2] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-5] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.962  INFO 65733 --- [nio-8080-exec-3] c.e.t.ThreadInitializer2                 : do something for thread init.
2020-05-02 14:50:15.986  INFO 65733 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-02 14:50:15.992  INFO 65733 --- [           main] c.e.t.ThreadInitOnDeploymentApplication  : Started ThreadInitOnDeploymentApplication in 14.269 seconds (JVM running for 15.023)

3. Reference