import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "thread.pool")
public class ThreadPoolProperties {
/**
* 核心线程池大小
*/
private int corePoolSize;
/**
* 最大可创建的线程数
*/
private int maxPoolSize;
/**
* 队列最大长度
*/
private int queueCapacity;
/**
* 线程池维护线程所允许的空闲时间
*/
private int keepAliveSeconds;
}
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
*
* ThreadPoolTaskExecutor 是 Spring 提供的一个方便的线程池实现,用于异步执行任务或处理并发请求。
*
* 在使用 ThreadPoolTaskExecutor 作为 Spring Bean 注册到容器中后,
* Spring 会负责在应用程序关闭时自动关闭所有注册的线程池,所以不需要手动关闭。
*
* 这样不仅可以确保线程池中的线程正确地停止,还可以防止资源泄露和潜在的并发问题。
*/
@Configuration
public class ThreadPoolConfig
{
//线程池配置
@Resource
private ThreadPoolProperties threadPoolProperties;
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
{
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
// 核心线程池大小
threadPool.setCorePoolSize(threadPoolProperties.getCorePoolSize());
// 最大可创建的线程数
threadPool.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
// 等待队列最大长度
threadPool.setQueueCapacity(threadPoolProperties.getQueueCapacity());
// 线程池维护线程所允许的空闲时间
threadPool.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
//异步方法内部线程名称
threadPool.setThreadNamePrefix("spring默认线程池-");
// 线程池对拒绝任务(无线程可用)的处理策略
threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 任务都完成再关闭线程池
threadPool.setWaitForTasksToCompleteOnShutdown(true);
// 任务初始化
threadPool.initialize();
return threadPool;
}
}
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
public class TaskBatchSendUtils
{
public static <T> void send(List<T> taskList, Executor threadPool, Consumer<? super T> consumer) throws InterruptedException
{
if (taskList == null || taskList.size() == 0)
{
return;
}
if(Objects.isNull(consumer))
{
return;
}
CountDownLatch countDownLatch = new CountDownLatch(taskList.size());
for (T couponOrShortMsg : taskList)
{
threadPool.execute(() ->
{
try
{
consumer.accept(couponOrShortMsg);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
}
public static void disposeTask(String task)
{
System.out.println(String.format("【%s】disposeTask下发优惠卷或短信成功", task));
}
public static void disposeTaskV2(String task)
{
System.out.println(String.format("【%s】disposeTask下发邮件成功", task));
}
public static void disposeTaskV3(String task)
{
System.out.println(String.format("【%s】disposeTask下发二维码序号成功", task));
}
}
import com.service.CouponServiceV2;
import com.utils.TaskBatchSendUtils;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class CouponServiceImplV2 implements CouponServiceV2
{
//下发优惠卷数量
public static final Integer COUPON_NUMBER = 50000;
@Resource
private ThreadPoolTaskExecutor threadPool;
@SneakyThrows
@Override
public void batchTaskActionV2()
{
//1 模拟要下发的5W条优惠卷,上游系统给我们的下发优惠卷源头
List<String> coupons = getCoupons();
long startTime = System.currentTimeMillis();
//2 调用工具类批处理任务,这些优惠卷coupons,放入线程池threadPool,做什么业务disposeTask下发
TaskBatchSendUtils.send(coupons,threadPool,TaskBatchSendUtils::disposeTaskV2);
long endTime = System.currentTimeMillis();
System.out.println("----costTime: "+(endTime - startTime) +" 毫秒");
}
private static List<String> getCoupons()
{
List<String> coupons = new ArrayList<>(COUPON_NUMBER);
for (int i = 1; i <= COUPON_NUMBER; i++)
{
coupons.add("优惠卷--"+i);
}
return coupons;
}
}