SpringBoot 多线程异步@Async + 信号量 Semaphore
Java 信号量 Semaphore
信号量是一种多线程同步工具,用于控制同时访问某个资源的线程数量。
信号量(Semaphore),在多线程环境下用于协调各个线程, 以保证它们能够正确、合理的使用公共资源.
比如 ClassA,B,C,D 都需要访问资源ClassCommon, 但是同时只能有2个线程同时访问资源ClassCommon时,就可以把ClassCommon包裹在Semaphore中
线程执行顺序 同一时间最多有3个线程在执行任务,其余线程会等待许可释放。
Semaphore semaphore = new Semaphore(3); //定义一个信号量,最多允许3个线程同时访问。 semaphore.acquire(); //获取一个许可,如果没有可用许可,线程会阻塞。 semaphore.release(); //释放一个许可,允许其他线程继续执行。
请用SpringBoot+线程池+Semaphore 实现以下需求
定义类ClassA, 实现方法methodA, 输出接收到的参数,并睡眠30s
定义类ClassB, 实现方法methodB, 顺序调用ClassA.methodA
定义类ClassC, 实现方法methodC, 开多线程调用ClassA.methodA,同时执行最大线程数10
并且同时调用ClassA.methodA方法的线程数最大是10个,该线程数包括ClassB的调用和ClassC的调用.
分析:
在这个场景中ClassA.methodA就是公共资源。
这个代码使用了ExecutorService来管理线程池,并使用Semaphore来限制同时处理的请求数量为10。
其余的请求会被阻塞,直到有处理完成的请求释放信号量
ThreadPoolTaskExecutor提供线程池支持, 实现异步方法ClassB.methodB
@Async注解实现异步调用ClassA.methodA
Semaphore控制同时调用ClassA.methodA的线程数不超过10。
定义线程池和信号量,开启异步
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; @Configuration @EnableAsync public class ThreadPoolAndSemaphoreConfig { @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程数 executor.setCorePoolSize(10); // 最大线程数 executor.setMaxPoolSize(50); // 队列容量 executor.setQueueCapacity(100); // 线程存活时间(秒) executor.setKeepAliveSeconds(60); // 线程名称前缀 executor.setThreadNamePrefix("AsyncExecutor-"); // 拒绝策略:抛出异常 executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.AbortPolicy()); // 初始化线程池 executor.initialize(); return executor; } @Bean public Semaphore semaphore() { // 限制同时访问公共的线程数量为 10 return new Semaphore(10); } }
ClassA, 用信号量控制
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.concurrent.Semaphore; @Service public class ClassA { private static final Logger logger = LoggerFactory.getLogger(ClassA.class); @Autowired private Semaphore semaphore; public void methodA(String param) throws InterruptedException { try { logger.info("before"); semaphore.acquire(); // Acquire a permit logger.info("acquired"); try { logger.info("Executing methodA with param: {}", param); Thread.sleep(30000); // Simulate a long-running task } finally { semaphore.release(); // Release the permit logger.info("released"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Thread interrupted", e); } } }
定义ClassB, 同步call ClassA
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.concurrent.Semaphore; @Service public class ClassB { @Autowired private ClassA classA; @Autowired private Semaphore semaphore; private static final Logger logger = LoggerFactory.getLogger(ClassB.class); public void methodB(String param) throws InterruptedException { classA.methodA(param); } }
定义ClassC, 异步callClassA
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.concurrent.Semaphore; @Service public class ClassC { @Autowired private ClassA classA; @Autowired private Semaphore semaphore; private static final Logger logger = LoggerFactory.getLogger(ClassC.class); @Async("taskExecutor") public void methodC(String param) throws InterruptedException { classA.methodA(param); } }
测试controller
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @Autowired private ClassC classC; @Autowired private ClassB classB; private static final Logger logger = LoggerFactory.getLogger(ClassB.class); @GetMapping("/testSequential") public String testSequential() throws InterruptedException { logger.info("testSequential"); classB.methodB("SequentialCall"); return "Sequential call completed"; } @GetMapping("/testConcurrent") public String testConcurrent() throws InterruptedException { logger.info("testConcurrent"); classC.methodC("ConcurrentCall-"); return "Concurrent calls initiated"; } }
同时处理ClassA请求的个数 = Semaphore可用量
同时处理ClassB请求的个数 = min(线程池可用线程,Semaphore可用量)
浙公网安备 33010602011771号