一、Bug 场景
在一个电商后台系统中,使用线程池来处理订单处理、库存更新、物流通知等多种异步任务。随着业务量的增长,系统逐渐出现响应变慢的情况,部分任务甚至长时间得不到执行,最终导致一些关键业务流程受阻。
二、代码示例
任务类
java
public class BusinessTask implements Runnable {
private final String taskName;
public BusinessTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
// 模拟业务处理
Thread.sleep(1000);
System.out.println(taskName + " 任务完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
线程池配置与任务提交(有缺陷)
java
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class EcommerceSystem {
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 20;
private static final long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
taskQueue);
// 模拟提交大量任务
for (int i = 0; i < 50; i++) {
String taskName = "任务 " + i;
executor.submit(new BusinessTask(taskName));
}
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("线程池未正常关闭");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
三、问题描述
-
预期行为:线程池能够高效处理提交的任务,所有任务都能在合理时间内完成,系统保持稳定运行。
-
实际行为:
- 任务堆积:随着任务不断提交,任务队列逐渐被填满,新任务只能等待队列有空位或者线程池创建新线程(达到最大线程数后也只能等待)。这是因为线程池的核心线程数和最大线程数设置相对业务量过小,并且任务执行时间较长,导致任务处理速度跟不上提交速度。
- 饥饿死锁:在任务队列中可能存在优先级不同的任务,例如订单处理任务优先级较高,物流通知任务优先级较低。如果高优先级任务持续提交,线程池中的线程会一直忙于处理高优先级任务,低优先级任务可能长时间得不到执行,出现饥饿现象。极端情况下,可能导致低优先级任务永远无法执行,形成一种类似死锁的状态。
四、解决方案
- 优化线程池参数:根据实际业务负载和任务特性,合理调整线程池参数。例如,如果任务执行时间较短且数量较多,可以适当增加核心线程数和最大线程数;如果任务执行时间较长,可以扩大任务队列容量。
java
private static final int CORE_POOL_SIZE = 10;
private static final int MAX_POOL_SIZE = 20;
private static final int QUEUE_CAPACITY = 50;
- 使用优先级队列和优先级线程池 :对任务进行优先级划分,使用
PriorityBlockingQueue作为任务队列,并自定义PriorityThreadPoolExecutor来处理不同优先级的任务。
java
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class PriorityBusinessTask implements Runnable, Comparable<PriorityBusinessTask> {
private final String taskName;
private final int priority;
public PriorityBusinessTask(String taskName, int priority) {
this.taskName = taskName;
this.priority = priority;
}
@Override
public void run() {
try {
// 模拟业务处理
Thread.sleep(1000);
System.out.println(taskName + " 任务完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public int compareTo(PriorityBusinessTask other) {
return Integer.compare(other.priority, this.priority);
}
}
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
if (r instanceof PriorityBusinessTask) {
System.out.println("开始执行优先级任务: " + ((PriorityBusinessTask) r).taskName);
}
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (r instanceof PriorityBusinessTask) {
System.out.println("完成优先级任务: " + ((PriorityBusinessTask) r).taskName);
}
}
}
public class EcommerceSystem {
private static final int CORE_POOL_SIZE = 10;
private static final int MAX_POOL_SIZE = 20;
private static final int QUEUE_CAPACITY = 50;
private static final long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
BlockingQueue<Runnable> taskQueue = new PriorityBlockingQueue<>(QUEUE_CAPACITY);
PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
taskQueue);
// 模拟提交不同优先级任务
executor.submit(new PriorityBusinessTask("高优先级任务 1", 1));
executor.submit(new PriorityBusinessTask("低优先级任务 1", 3));
executor.submit(new PriorityBusinessTask("高优先级任务 2", 1));
executor.submit(new PriorityBusinessTask("低优先级任务 2", 3));
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("线程池未正常关闭");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
- 动态调整线程池:根据系统运行时的任务队列长度、线程池活跃线程数等指标,动态调整线程池的参数,以适应业务量的变化。可以使用定时任务定期检查并调整线程池大小。
java
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class EcommerceSystem {
private static final int INITIAL_CORE_POOL_SIZE = 5;
private static final int INITIAL_MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 20;
private static final long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
INITIAL_CORE_POOL_SIZE,
INITIAL_MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
taskQueue);
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
scheduler.scheduleAtFixedRate(() -> {
int queueSize = taskQueue.size();
int activeCount = executor.getActiveCount();
if (queueSize > QUEUE_CAPACITY * 0.8 && activeCount < INITIAL_MAX_POOL_SIZE) {
executor.setCorePoolSize(executor.getCorePoolSize() + 1);
executor.setMaximumPoolSize(executor.getMaximumPoolSize() + 1);
} else if (queueSize < QUEUE_CAPACITY * 0.2 && activeCount > INITIAL_CORE_POOL_SIZE) {
executor.setCorePoolSize(executor.getCorePoolSize() - 1);
executor.setMaximumPoolSize(executor.getMaximumPoolSize() - 1);
}
}, 0, 1, TimeUnit.MINUTES);
// 模拟提交大量任务
for (int i = 0; i < 50; i++) {
String taskName = "任务 " + i;
executor.submit(new BusinessTask(taskName));
}
executor.shutdown();
scheduler.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("线程池未正常关闭");
}
}
if (!scheduler.awaitTermination(1, TimeUnit.MINUTES)) {
scheduler.shutdownNow();
if (!scheduler.awaitTermination(1, TimeUnit.MINUTES)) {
System.err.println("调度器未正常关闭");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}