<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Java Knowledge Ocean: Spring, Spring Boot]]></title><description><![CDATA[Share knowledge and usage skills related to the Spring and Spring Boot frameworks.]]></description><link>https://seabreeze0828.substack.com/s/spring-spring-boot</link><image><url>https://substackcdn.com/image/fetch/$s_!MgS-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2006b880-951e-4af1-8243-52e5cdef4c73_676x676.png</url><title>The Java Knowledge Ocean: Spring, Spring Boot</title><link>https://seabreeze0828.substack.com/s/spring-spring-boot</link></image><generator>Substack</generator><lastBuildDate>Thu, 20 Aug 2026 12:54:43 GMT</lastBuildDate><atom:link href="https://seabreeze0828.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dylan Smith]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[dylan0828@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[dylan0828@substack.com]]></itunes:email><itunes:name><![CDATA[Dylan Smith]]></itunes:name></itunes:owner><itunes:author><![CDATA[Dylan Smith]]></itunes:author><googleplay:owner><![CDATA[dylan0828@substack.com]]></googleplay:owner><googleplay:email><![CDATA[dylan0828@substack.com]]></googleplay:email><googleplay:author><![CDATA[Dylan Smith]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[How Does Spring Boot Implement Asynchronous Programming? This Is How Masters Do It!]]></title><description><![CDATA[Why default @Async causes memory leaks and how to build production-ready thread pools with AsyncConfigurer.]]></description><link>https://seabreeze0828.substack.com/p/how-does-spring-boot-implement-asynchronous</link><guid isPermaLink="false">https://seabreeze0828.substack.com/p/how-does-spring-boot-implement-asynchronous</guid><dc:creator><![CDATA[Dylan Smith]]></dc:creator><pubDate>Fri, 14 Aug 2026 15:05:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!m_UL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m_UL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m_UL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 424w, https://substackcdn.com/image/fetch/$s_!m_UL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 848w, https://substackcdn.com/image/fetch/$s_!m_UL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 1272w, https://substackcdn.com/image/fetch/$s_!m_UL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m_UL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png" width="883" height="454" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/caa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:454,&quot;width&quot;:883,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;@Async&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="@Async" title="@Async" srcset="https://substackcdn.com/image/fetch/$s_!m_UL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 424w, https://substackcdn.com/image/fetch/$s_!m_UL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 848w, https://substackcdn.com/image/fetch/$s_!m_UL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 1272w, https://substackcdn.com/image/fetch/$s_!m_UL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa5354a-bf8d-4aca-820a-bc150b25bbcf_883x454.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://seabreeze0828.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Java Knowledge Ocean is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Today, let&#8217;s talk about how to implement <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">asynchronous programming in a Spring Boot project. First, let&#8217;s see why asynchronous programming </mark>is used in Spring and what problems it can solve.</p><h2><strong>Why use an <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">asynchronous</mark> framework and what problems does it solve?</strong></h2><p>In the daily development of Spring Boot, synchronous calls are generally used. However, in reality, there are many scenarios that are very suitable for <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">asynchronous processing</mark>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JjRD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JjRD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 424w, https://substackcdn.com/image/fetch/$s_!JjRD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 848w, https://substackcdn.com/image/fetch/$s_!JjRD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 1272w, https://substackcdn.com/image/fetch/$s_!JjRD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JjRD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png" width="1037" height="484" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:484,&quot;width&quot;:1037,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!JjRD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 424w, https://substackcdn.com/image/fetch/$s_!JjRD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 848w, https://substackcdn.com/image/fetch/$s_!JjRD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 1272w, https://substackcdn.com/image/fetch/$s_!JjRD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e1050d1-763f-402d-a351-bb7f53506995_1037x484.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">For example, when registering a new user, an email reminder will be sent. Later, when you upgrade to a member, you will be given 1000 points and other scenarios.</mark></p><p>Taking the use case of registering a new user as an example, why is asynchronous processing necessary? There are mainly two aspects:</p><ol><li><p><strong>Fault tolerance and robustness</strong>: If an exception occurs when sending an email, the user registration cannot fail because of the failure of email sending. Because user registration is the main function and sending an email is a secondary function. When the user cannot receive the email but can see and log in to the system, they won&#8217;t care about the email.</p></li><li><p><strong>Improving interface performance</strong>: For example, it takes 20 milliseconds to register a user and 2000 milliseconds to send an email. If synchronous mode is used, the total time consumption is about 2020 milliseconds, and the user can clearly feel sluggish. But if asynchronous mode is used, registration can be successful in just a few tens of milliseconds. This is an instant thing.</p></li></ol><h2><strong>How does Spring Boot implement<mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> asynchronous calls?</mark></strong></h2><p>After knowing why asynchronous calls are needed, let&#8217;s see how Spring Boot implements such code.</p><p>In fact, it is very simple. <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">Starting from Spring 3, the </mark><code>@Async</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> annotation is provided. We only need to mark this annotation on the method, and this method can implement asynchronous calls.</mark></p><p>Of course, we also need a configuration class and add the annotation <code>@EnableAsync</code> to the configuration class to enable asynchronous functions.</p><h3><strong>First step: Create a configuration class and enable asynchronous function support</strong></h3><p>Use <code>@EnableAsync</code> to enable asynchronous task support. <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">The </mark><code>@EnableAsync</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> annotation can be directly placed on the </mark><code>Spring Boot</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> startup class or on other configuration classes separately. Here we choose to use a separate configuration class </mark><code>SyncConfiguration</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">.</mark></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;73227a77-6394-4192-8b66-4aab213f7c0a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">@Configuration
@EnableAsync
public class AsyncConfiguration {
   // do nothing 
}</code></pre></div><h3><strong>Second step: Mark the method as an asynchronous call</strong></h3><p>Add a <code>Component</code> class for business processing. At the same time, add the <code>@Async</code> annotation, which indicates that this method is asynchronous processing.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;05d74f51-3247-4055-9f24-e256dc4ceb50&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Component
public class AsyncTask {

    @Async
    public void sendEmail() {
        long t1 = System.currentTimeMillis();
        Thread.sleep(2000);
        long t2 = System.currentTimeMillis();
        System.out.println(&#8221;Sending an email took &#8220; + (t2-t1) + &#8220; ms&#8221;);
    }
}</code></pre></div><h3><strong>Third step: Call asynchronous methods in the Controller.</strong></h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;fdfa301a-a458-4f25-86c2-d4e97e8db21b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@RestController
@RequestMapping(&#8221;/user&#8221;)
public class AsyncController {

    @Autowired
    private AsyncTask asyncTask;

    @RequestMapping(&#8221;/register&#8221;)
    public void register() throws InterruptedException {
        long t1 = System.currentTimeMillis();
        // Simulate the time required for user registration.
        Thread.sleep(20);
        // Registration is successful. Send an email.
        asyncTask.sendEmail();
        long t2 = System.currentTimeMillis();
        System.out.println(&#8221;Registering a user took &#8220; + (t2-t1) + &#8220; ms&#8221;);
    }
}</code></pre></div><p>After accessing <code>http://localhost:8080/user/register</code>, view the console log.</p><pre><code><span>Registering a user took 29 ms
Sending an email took 2006 ms</span></code></pre><p>As can be seen from the log, the main thread does not need to wait for the execution of the<mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> email sending method to complete before returning, effectively reducing the response time and improving the interface</mark> performance.</p><p>Through the above three steps, we can easily use asynchronous methods in Spring Boot to improve our interface performance. Isn&#8217;t it very simple?</p><p><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">However, if you really implement it this way in a company project, it will definitely be rejected during code review and you may even be reprimanded. </mark>&#128555;</p><p>Because the above code ignores the biggest problem, which is that a custom thread pool has not been provided for the <code>@Async</code> asynchronous framework.</p><h2><strong>Why should we <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">customize</mark> a thread pool for </strong><code>@Async</code><strong>?</strong></h2><p><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">When using the </mark><code>@Async</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> annotation, by default, the </mark><code>SimpleAsyncTaskExecutor</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> thread pool is used. This thread pool is not a true thread pool.</mark></p><p><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">Using this thread pool cannot achieve thread reuse. A new thread will be created every time it is called. If threads are continuously created in the system, it will eventually lead to excessive memory usage by the system and cause an </mark><code>OutOfMemoryError</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">!!!</mark></p><p>The key code is as follows:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;488f5239-fd72-4ee2-b575-9892d1dcf06a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">public void execute(Runnable task, long startTimeout) {
      Assert.notNull(task, &#8220;Runnable must not be null&#8221;);
      Runnable taskToUse = this.taskDecorator != null ? this.taskDecorator.decorate(task) : task;
      // Determine whether rate limiting is enabled. By default, it is not enabled.
      if (this.isThrottleActive() &amp;&amp; startTimeout &gt; 0L) {
            // Perform pre-operations and implement rate limiting.
            this.concurrencyThrottle.beforeAccess();
            this.doExecute(new SimpleAsyncTaskExecutor.ConcurrencyThrottlingRunnable(taskToUse));
      } else {
            // In the case of no rate limiting, execute thread tasks.
            this.doExecute(taskToUse);
      }
}

protected void doExecute(Runnable task) {
      // Continuously create threads.
      Thread thread = this.threadFactory != null ? this.threadFactory.newThread(task) : this.createThread(task);
      thread.start();
}

public Thread createThread(Runnable runnable) {
     //Specify the thread name, task-1, task-2, task-3...
      Thread thread = new Thread(this.getThreadGroup(), runnable, this.nextThreadName());
      thread.setPriority(this.getThreadPriority());
      thread.setDaemon(this.isDaemon());
      return thread;
}</code></pre></div><p><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">If you output the thread name again, it can be easily found that each time the printed thread name is in the form of [task-1], [task-2], [task-3], [task-4], and the serial number at the back is continuously increasing.</mark></p><p><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">For this reason, when using the </mark><code>@Async</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> asynchronous framework in Spring, we must customize a thread pool to replace the default </mark><code>SimpleAsyncTaskExecutor</code><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">.</mark></p><p>Spring provides a variety of thread pools to choose from:</p><ul><li><p><code>SimpleAsyncTaskExecutor</code>: <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">Not a real thread pool. This class does not reuse threads and creates a new thread every time it is called.</mark></p></li><li><p><code>SyncTaskExecutor</code>: This class does not implement asynchronous calls and is only a synchronous operation. Only applicable to scenarios where multithreading is not needed.</p></li><li><p><code>ConcurrentTaskExecutor</code>: An adaptation class for Executor. Not recommended. Consider using this class only when ThreadPoolTaskExecutor does not meet the requirements.</p></li><li><p><code>ThreadPoolTaskScheduler</code>: Can use cron expressions.</p></li><li><p><code>ThreadPoolTaskExecutor</code>: <strong>Most commonly used and recommended</strong>. In essence, it is a wrapper for java.util.concurrent.ThreadPoolExecutor.</p></li></ul><p>The implementation paths of <code>SimpleAsyncTaskExecutor</code> and <code>ThreadPoolTaskExecutor</code> are as follows:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fiSh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fiSh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 424w, https://substackcdn.com/image/fetch/$s_!fiSh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 848w, https://substackcdn.com/image/fetch/$s_!fiSh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 1272w, https://substackcdn.com/image/fetch/$s_!fiSh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fiSh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png" width="1259" height="613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:613,&quot;width&quot;:1259,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!fiSh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 424w, https://substackcdn.com/image/fetch/$s_!fiSh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 848w, https://substackcdn.com/image/fetch/$s_!fiSh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 1272w, https://substackcdn.com/image/fetch/$s_!fiSh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db60766-fa52-4101-b50b-08e452dd3dec_1259x613.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Implement a custom thread pool</strong></h2><p>Let&#8217;s directly look at the code implementation. Here, a thread pool named <code>asyncPoolTaskExecutor</code> is implemented:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;d0598c88-501f-4599-a4c4-94b4ea4309e2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Configuration
@EnableAsync
public class SyncConfiguration {
    @Bean(name = &#8220;myAsyncPoolTaskExecutor&#8221;)
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // Core thread count.
        taskExecutor.setCorePoolSize(10);
        // The maximum number of threads maintained in the thread pool. Only when the buffer queue is full will threads exceeding the core thread count be requested.
        taskExecutor.setMaxPoolSize(100);
        // Cache queue.
        taskExecutor.setQueueCapacity(50);
        // Allowed idle time. Threads other than core threads will be destroyed after the idle time arrives.
        taskExecutor.setKeepAliveSeconds(200);
        // Thread name prefix for asynchronous methods.
        taskExecutor.setThreadNamePrefix(&#8221;async-&#8221;);
        /**
         * When the task cache queue of the thread pool is full and the number of threads in the thread pool reaches maximumPoolSize, if there are still tasks coming, a task rejection policy will be adopted.
         * There are usually four policies:
         * ThreadPoolExecutor.AbortPolicy: Discard the task and throw RejectedExecutionException.
         * ThreadPoolExecutor.DiscardPolicy: Also discard the task, but do not throw an exception.
         * ThreadPoolExecutor.DiscardOldestPolicy: Discard the task at the front of the queue and then try to execute the task again (repeat this process).
         * ThreadPoolExecutor.CallerRunsPolicy: Retry adding the current task and automatically call the execute() method repeatedly until it succeeds.
         */
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.initialize();
        return taskExecutor;
    }
}</code></pre></div><p>Congratulations! After customizing the thread pool, we can boldly use the asynchronous processing capability provided by <code>@Async</code>. &#128522;</p><h3><strong><mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">Configure</mark> multiple thread pools</strong></h3><p>In the development of real Internet projects, for high-concurrency requests, the general approach is to isolate high-concurrency interfaces with separate thread pools for processing.</p><p>Suppose there are currently two high-concurrency interfaces. Generally, two thread pools will be defined according to the interface characteristics. At this time, when we use <code>@Async</code>, we need to distinguish by specifying different thread pool names.</p><h2><strong>Specify a specific thread pool for </strong><code>@Async</code></h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;5352ef87-0430-412d-8a62-e8b8e49a30fb&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Async(&#8221;myAsyncPoolTaskExecutor&#8221;)
public void sendEmail() {
    long t1 = System.currentTimeMillis();
    Thread.sleep(2000);
    long t2 = System.currentTimeMillis();
    System.out.println(&#8221;Sending an email took &#8220; + (t2-t1) + &#8220; ms&#8221;);
}</code></pre></div><p>When there are multiple thread pools in the system, we can also configure a default thread pool. For non-default asynchronous tasks, we can specify the thread pool name through <code>@Async("otherTaskExecutor")</code>.</p><h3><strong>Configure the default thread pool</strong></h3><p>The configuration class can be modified to implement <code>AsyncConfigurer</code> and override the <code>getAsyncExecutor()</code> method to specify the default thread pool:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;f492bcb2-b679-4c3e-9cd2-8e6af9ce0865&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Configuration
@EnableAsync
@Slf4j
public class AsyncConfiguration implements AsyncConfigurer {

    @Bean(name = &#8220;myAsyncPoolTaskExecutor&#8221;)
    public ThreadPoolTaskExecutor executor() {
        // Initialization code for thread pool configuration as above.
    }

    @Bean(name = &#8220;otherTaskExecutor&#8221;)
    public ThreadPoolTaskExecutor otherExecutor() {
        // Initialization code for thread pool configuration as above.
    }

    /**
     * Specify the default thread pool.
     */
    @Override
    public Executor getAsyncExecutor() {
        return executor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -&gt;
                log.error(&#8221;An unknown error occurred while executing tasks in the thread pool. Executing method: {}&#8221;, method.getName(), ex);
    }
}</code></pre></div><p>As follows, the <code>sendEmail()</code> method uses the default thread pool <code>myAsyncPoolTaskExecutor</code>, and the <code>otherTask()</code> method uses the thread pool <code>otherTaskExecutor</code>, which is very flexible.</p><pre><code><span>@Async(&#8221;myAsyncPoolTaskExecutor&#8221;)
public void sendEmail() {
    long t1 = System.currentTimeMillis();
    Thread.sleep(2000);
    long t2 = System.currentTimeMillis();
    System.out.println(&#8221;Sending an email took &#8220; + (t2-t1) + &#8220; ms&#8221;);
}

@Async(&#8221;otherTaskExecutor&#8221;)
public void otherTask() {
    //...
}</span></code></pre><p>Many times, <a href="http://twitter.com/Async">@Async</a> is often used in conjunction with Spring Event to optimize the code structure, interested parties can read <a href="https://levelup.gitconnected.com/springboot-combine-spring-event-with-async-annotation-for-effortless-code-decoupling-and-7bb17942f20a?sharedUserId=junfeng0828">this article.</a></p><p>The <mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);">above</mark> is all the content shared this time! <strong>If the article was helpful, please clap &#128079;and follow, thank you! &#9584;(*&#176;&#9661;&#176;*)&#9583;*</strong>*</p><p><strong>I&#8217;m Dylan, looking forward to progressing with you. &#10084;&#65039;</strong></p>]]></content:encoded></item></channel></rss>