diff --git a/README.md b/README.md index b0f9262..f017745 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,18 @@ # 使用 `@Async` 实现线程池 +```mermaid +graph TD + A[调用者调用异步方法] --> B[Spring AOP 代理拦截方法调用] + B --> C{方法是否为 @Async?} + C -->|是| D[封装为 FutureTask 或 Runnable] + C -->|否| E[按正常方式执行] + D --> F[提交到线程池 TaskExecutor] + F --> G[线程池分配一个线程] + G --> H[JVM 创建线程并执行任务] + H --> I[任务执行完毕,返回结果] + I --> J[调用者通过 Future 获取结果] +``` + ## 前置知识 ### **`@Async`** diff --git a/src/main/java/cn/hezhaohui/threadpool/conifg/AsyncConfig.java b/src/main/java/cn/hezhaohui/threadpool/conifg/AsyncConfig.java new file mode 100644 index 0000000..98bc629 --- /dev/null +++ b/src/main/java/cn/hezhaohui/threadpool/conifg/AsyncConfig.java @@ -0,0 +1,27 @@ +package cn.hezhaohui.threadpool.conifg; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +/** + * 异步配置类 + */ +@Configuration +@EnableAsync +public class AsyncConfig { + + @Bean(name = "customThreadPool") + public Executor customThreadPool() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(5); + executor.setMaxPoolSize(10); + executor.setQueueCapacity(100); + executor.setThreadNamePrefix("Custom-Async-"); + executor.initialize(); + return executor; + } +} diff --git a/src/main/java/cn/hezhaohui/threadpool/service/AsyncService.java b/src/main/java/cn/hezhaohui/threadpool/service/AsyncService.java new file mode 100644 index 0000000..c8c8ac5 --- /dev/null +++ b/src/main/java/cn/hezhaohui/threadpool/service/AsyncService.java @@ -0,0 +1,44 @@ +package cn.hezhaohui.threadpool.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; + +@Service +@Slf4j +public class AsyncService { + + @Async("customThreadPool") + public void asyncPrint() { + String id = UUID.randomUUID().toString().substring(0, 5); + int sleepSeconds = new Random().nextInt(15); + log.info("[Thread {}] Called, waiting {} seconds", id, sleepSeconds); + try { + Thread.sleep(sleepSeconds * 1000L); + log.info("[Thread {}] Wait completed after {} seconds", id, sleepSeconds); + } catch (InterruptedException e) { + log.error("[Thread {}] Interrupted during wait", id, e); + Thread.currentThread().interrupt(); + } + } + + @Async("customThreadPool") + public void asyncPrint(CountDownLatch latch) { + String id = UUID.randomUUID().toString().substring(0, 5); + int sleepSeconds = new Random().nextInt(15); + log.info("[Thread {}] ⚠️ Called, waiting {} seconds", id, sleepSeconds); + try { + Thread.sleep(sleepSeconds * 1000L); + log.info("[Thread {}] ✅ Wait completed after {} seconds", id, sleepSeconds); + } catch (InterruptedException e) { + log.error("[Thread {}] Interrupted during wait", id, e); + Thread.currentThread().interrupt(); + } finally { + latch.countDown(); + } + } +} diff --git a/src/test/java/cn/hezhaohui/threadpool/service/AsyncServiceTest.java b/src/test/java/cn/hezhaohui/threadpool/service/AsyncServiceTest.java new file mode 100644 index 0000000..307fce0 --- /dev/null +++ b/src/test/java/cn/hezhaohui/threadpool/service/AsyncServiceTest.java @@ -0,0 +1,29 @@ +package cn.hezhaohui.threadpool.service; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.concurrent.CountDownLatch; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +@Slf4j +class AsyncServiceTest { + + @Resource + private AsyncService asyncService; + + @Test + void asyncPrint() throws InterruptedException { + CountDownLatch latch = new CountDownLatch(15); + for (int i = 0; i < 200; i++) { + asyncService.asyncPrint(latch); + } + log.info("\n[+++ All Tasks Commited +++]\n"); + latch.await(); + log.info("\n[=== All Tasks Completed ===]\n"); + } +} \ No newline at end of file