深度解析:Executors 工具类实现线程池的 4 种方式(含源码 + 避坑)
wptr33 2025-09-19 03:55 1 浏览
作为 Java 开发人员,
java.util.concurrent.Executors工具类一定不陌生 —— 它是 JDK 为简化线程池创建提供的 “快捷方式”,通过 4 个静态方法就能快速实例化不同类型的线程池,无需手动配置复杂参数。但 “快捷” 往往伴随着 “隐藏风险”,阿里巴巴 Java 开发手册明确禁止其在生产环境使用,核心原因就是部分实现存在资源耗尽隐患。
本文将从用法细节、源码原理、实战问题、替代方案四个维度,彻底讲透 Executors 工具类的 4 种线程池实现,帮你既懂 “怎么用”,更懂 “为什么不能这么用”。
Executors 工具类的设计初衷与底层逻辑
在拆解具体实现前,先明确一个核心认知:Executors 本质是 ThreadPoolExecutor 的 “封装器”。
JDK 开发者考虑到新手难以掌握 ThreadPoolExecutor 的 7 个核心参数(如核心线程数、任务队列、拒绝策略等),便通过 Executors 封装了 4 种高频场景的线程池配置,让开发者只需一行代码即可创建线程池。其底层逻辑可概括为:
// Executors的静态方法 = 预设参数的ThreadPoolExecutor实例化
public static ExecutorService newFixedThreadPool(int nThreads) {
// 核心参数已固化:核心线程数=最大线程数,无界队列,非核心线程存活时间0
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
所有 Executors 创建的线程池,最终都指向 ThreadPoolExecutor 实例,只是参数组合不同。而正是这些 “固化的参数”,导致了不同场景下的风险差异。
方式 1:newFixedThreadPool—— 固定大小的线程池
核心特性与适用场景
- 线程数量固定:核心线程数(corePoolSize)= 最大线程数(maximumPoolSize),一旦创建不会增减,即使线程空闲也不会销毁(除非线程池关闭)。
- 任务队列无界:使用LinkedBlockingQueue(默认容量Integer.MAX_VALUE,约 21 亿),可无限接收任务,避免任务被拒绝。
- 适用场景:任务量已知、并发度固定的场景,如 “后台批量处理 1000 条订单数据,每次并发 5 个任务”“定时同步数据库表数据,固定 3 个线程执行”。
完整用法示例(含任务监控)
public class FixedThreadPoolDemo {
public static void main(String[] args) {
// 1. 创建固定大小为3的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
// 2. 提交10个任务(模拟批量处理)
for (int i = 0; i < 10; i++) {
int taskId = i;
// 使用submit而非execute,可获取任务执行结果/异常
Future<?> future = fixedThreadPool.submit(() -> {
System.out.printf("[任务%d] 开始执行,线程名:%s%n",
taskId, Thread.currentThread().getName());
try {
// 模拟任务耗时(1-3秒随机)
Thread.sleep(new Random().nextInt(2000) + 1000);
} catch (InterruptedException e) {
System.out.printf("[任务%d] 被中断,原因:%s%n", taskId, e.getMessage());
Thread.currentThread().interrupt(); // 保留中断状态
}
System.out.printf("[任务%d] 执行完成%n", taskId);
return taskId; // 任务执行结果
});
// 3. 监控任务结果(非必须,按需使用)
try {
Object result = future.get(5, TimeUnit.SECONDS); // 超时时间5秒
System.out.printf("[任务%d] 结果:%s%n", taskId, result);
} catch (InterruptedException e) {
System.out.printf("[任务%d] 获取结果时被中断%n", taskId);
} catch (ExecutionException e) {
System.out.printf("[任务%d] 执行异常:%s%n", taskId, e.getCause().getMessage());
} catch (TimeoutException e) {
System.out.printf("[任务%d] 获取结果超时(5秒)%n", taskId);
future.cancel(true); // 超时后取消任务
}
}
// 4. 关闭线程池(关键步骤,避免线程泄漏)
fixedThreadPool.shutdown();
// 等待线程池关闭(最多等10秒)
try {
if (!fixedThreadPool.awaitTermination(10, TimeUnit.SECONDS)) {
fixedThreadPool.shutdownNow(); // 强制关闭未执行的任务
}
} catch (InterruptedException e) {
fixedThreadPool.shutdownNow();
}
System.out.println("线程池已关闭");
}
}
关键注意点:
- 必须调用shutdown()或shutdownNow()关闭线程池,否则核心线程会一直存活,导致 JVM 无法退出。
- submit()比execute()更灵活,支持获取任务结果和超时控制,适合需要监控任务状态的场景。
源码解析:为什么会有 OOM 风险?
从newFixedThreadPool的源码可知,其任务队列是LinkedBlockingQueue的默认构造:
// LinkedBlockingQueue默认构造(无参)
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE); // 容量=2^31-1≈21亿
}
当任务提交速度远大于线程处理速度时(如每秒提交 1000 个任务,3 个线程每秒仅能处理 3 个),任务会在队列中持续积压。每个任务都是一个对象,会占用堆内存,当队列中任务数达到数百万甚至数千万时,会触发
java.lang.OutOfMemoryError: Java heap space。
实战案例:某电商项目用newFixedThreadPool(5)处理订单支付回调,秒杀活动期间每秒产生 5000 个回调任务,线程每秒仅能处理 20 个,1 小时后队列积压 1700 万 + 任务,堆内存从 2G 暴涨到 8G,最终服务宕机。
替代方案:生产环境如何安全实现 “固定线程池”?
核心思路:用 ThreadPoolExecutor 手动配置,将任务队列改为有界队列,并指定合理的拒绝策略。示例:
// 安全的固定大小线程池(8核CPU场景)
ExecutorService safeFixedThreadPool = new ThreadPoolExecutor(
5, // 核心线程数(根据业务调整)
5, // 最大线程数=核心线程数(固定大小)
0L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(1000), // 有界队列,容量1000(避免积压)
new CustomThreadFactory("order-callback"), // 自定义线程工厂(便于排查)
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略(调用者线程执行,减缓提交速度)
);
方式 2:newCachedThreadPool—— 可缓存的线程池
核心特性与适用场景
- 线程动态伸缩:核心线程数 = 0,最大线程数 = Integer.MAX_VALUE(理论上可创建无限线程),线程空闲 60 秒后自动销毁。
- 任务队列特殊:使用SynchronousQueue(同步队列),不存储任务 —— 提交任务时必须有空闲线程接收,否则立即创建新线程。
- 适用场景:任务执行时间短、任务量波动大的场景,如 “接口异步回调通知(单次执行 50ms)”“临时数据校验(每秒任务量 0-1000 波动)”。
完整用法示例(含线程回收监控)
public class CachedThreadPoolDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 创建可缓存线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 2. 模拟分3波提交任务(每波间隔70秒,观察线程回收)
for (int wave = 1; wave <= 3; wave++) {
System.out.printf("=== 第%d波任务开始提交 ===%n", wave);
int taskCount = wave * 5; // 第1波5个任务,第2波10个,第3波15个
for (int i = 0; i < taskCount; i++) {
int taskId = (wave - 1) * 10 + i;
cachedThreadPool.execute(() -> {
System.out.printf("[任务%d] 执行中,线程名:%s%n",
taskId, Thread.currentThread().getName());
try {
Thread.sleep(500); // 模拟短任务(500ms)
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// 打印当前线程池状态(需通过反射获取,JDK无直接API)
printThreadPoolStatus(cachedThreadPool, "第" + wave + "波任务提交后");
// 间隔70秒(超过线程空闲60秒,观察线程回收)
Thread.sleep(70000);
}
// 3. 关闭线程池
cachedThreadPool.shutdown();
}
// 反射获取线程池状态(核心线程数、活跃线程数、队列任务数)
private static void printThreadPoolStatus(ExecutorService executor, String label) {
if (executor instanceof ThreadPoolExecutor) {
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
System.out.printf("[%s] 核心线程数:%d,活跃线程数:%d,队列任务数:%d%n",
label, pool.getCorePoolSize(),
pool.getActiveCount(), pool.getQueue().size());
}
}
}
执行结果关键观察:
- 第 1 波提交 5 个任务后,活跃线程数 = 5;70 秒后线程空闲超过 60 秒,活跃线程数降至 0(线程被回收)。
- 第 2 波提交 10 个任务时,会重新创建 10 个线程,执行完后 70 秒再次回收,避免资源浪费。
源码解析:为什么会触发 “线程爆炸”?
newCachedThreadPool的核心参数配置如下:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
风险点集中在两点:
最大线程数无上限:Integer.MAX_VALUE意味着理论上可创建 21 亿个线程,而每个线程默认占用 1M 栈内存(可通过-Xss调整),创建 1000 个线程就占用 1G 内存,创建 10 万个线程会直接导致 OOM。
同步队列无缓冲:SynchronousQueue不存储任务,当没有空闲线程时,提交任务会立即创建新线程。若任务执行时间意外变长(如原本 50ms 的任务因接口超时变成 5 秒),会导致线程数暴增。
实战案例:某 API 网关用newCachedThreadPool处理请求日志异步打印,正常情况下日志打印耗时 10ms,线程数稳定在 10 左右。某天日志服务故障,打印耗时增至 3 秒,1 分钟内线程数从 10 飙升到 12000,导致 CPU 使用率达 100%(上下文切换频繁),网关无法处理正常请求。
替代方案:生产环境如何安全实现 “可缓存线程池”?
核心思路:限制最大线程数,避免线程无限创建,同时保留 “线程自动回收” 的特性。示例:
// 安全的可缓存线程池(8核CPU场景)
ExecutorService safeCachedThreadPool = new ThreadPoolExecutor(
0, // 核心线程数=0(无长期存活线程)
50, // 最大线程数=50(限制线程上限,避免爆炸)
60L,
TimeUnit.SECONDS,
new SynchronousQueue<>(),
new CustomThreadFactory("api-log"),
new ThreadPoolExecutor.DiscardOldestPolicy() // 拒绝策略(丢弃旧任务,保留新任务)
);
方式 3:newSingleThreadExecutor—— 单线程线程池
核心特性与适用场景
- 单线程串行执行:核心线程数 = 1,最大线程数 = 1,所有任务按提交顺序(FIFO)由同一个线程执行。
- 线程故障自动恢复:若唯一的线程因异常终止,会自动创建一个新线程替代,保证任务不中断。
- 任务队列无界:同样使用LinkedBlockingQueue(默认容量 21 亿),避免任务被拒绝。
- 适用场景:需要串行执行的任务,如 “数据库表数据同步(避免并发修改主键冲突)”“日志文件写入(避免多线程写文件错乱)”“定时任务调度(确保任务按顺序执行)”。
完整用法示例(含线程恢复验证)
public class SingleThreadExecutorDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 创建单线程线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 2. 提交5个任务,第3个任务故意抛出异常(验证线程恢复)
for (int i = 0; i < 5; i++) {
int taskId = i;
singleThreadPool.submit(() -> {
String threadName = Thread.currentThread().getName();
System.out.printf("[任务%d] 开始执行,线程名:%s%n", taskId, threadName);
try {
if (taskId == 2) {
// 第3个任务故意抛出异常
throw new RuntimeException("任务执行异常(模拟故障)");
}
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.printf("[任务%d] 被中断,线程名:%s%n", taskId, threadName);
} catch (RuntimeException e) {
System.out.printf("[任务%d] 执行异常,线程名:%s,原因:%s%n",
taskId, threadName, e.getMessage());
// 异常无需捕获,线程池会自动处理并创建新线程
}
System.out.printf("[任务%d] 执行完成,线程名:%s%n", taskId, threadName);
});
Thread.sleep(500); // 间隔提交,便于观察顺序
}
// 3. 关闭线程池
singleThreadPool.shutdown();
singleThreadPool.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("线程池已关闭");
}
}
执行结果关键观察:
- 任务 0、1 由 “pool-1-thread-1” 执行;
- 任务 2 抛出异常后,“pool-1-thread-1” 终止;
- 任务 3、4 自动由新创建的 “pool-1-thread-2” 执行,实现故障恢复。
源码解析:风险与 “伪单线程” 问题
newSingleThreadExecutor的源码如下:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(
new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>())
);
}
(1)核心风险:无界队列导致 OOM
与newFixedThreadPool一致,任务队列是LinkedBlockingQueue(无界),当任务提交速度超过单线程处理速度时,队列会持续积压,最终触发 OOM。
(2)隐藏问题:无法强制修改线程数(伪单线程)
FinalizableDelegatedExecutorService是一个包装类,它屏蔽了ThreadPoolExecutor的setCorePoolSize()、setMaximumPoolSize()等方法,意味着一旦创建,无法通过代码动态调整线程数。若业务场景需要临时增加线程数(如紧急数据同步),只能重新创建线程池,灵活性差。
替代方案:生产环境如何安全实现 “单线程线程池”?
核心思路:手动创建 ThreadPoolExecutor,使用有界队列,保留动态调整线程数的能力。示例:
// 安全的单线程线程池
ThreadPoolExecutor safeSingleThreadPool = new ThreadPoolExecutor(
1, // 核心线程数=1
1, // 最大线程数=1(默认单线程)
0L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(500), // 有界队列,容量500
new CustomThreadFactory ("data-sync"), // 自定义线程工厂
new ThreadPoolExecutor.AbortPolicy () // 拒绝策略(数据同步任务重要,抛异常提醒)
);
// 如需临时调整线程数(如紧急同步),可动态修改
safeSingleThreadPool.setMaximumPoolSize (3);
方式4:newScheduledThreadPool——支持定时/周期性任务的线程池
核心特性与适用场景
- 线程数动态调整:核心线程数可手动指定(固定),最大线程数= `Integer.MAX_VALUE`(理论无上限),非核心线程空闲后立即销毁(无存活时间配置)。
- 任务队列特殊:使用`DelayedWorkQueue`(延迟队列),任务按“执行时间”排序,只有到达指定时间才会被线程取出执行。
支持3类定时任务:
- 延迟执行:任务提交后,延迟N时间再执行1次;
- 固定延迟执行:任务执行完后,间隔N时间再执行下一次(以上次任务结束时间为起点);
- 固定频率执行:任务开始执行后,间隔N时间再执行下一次(以上次任务开始时间为起点)。
适用场景:需定时执行的任务,如“每天凌晨2点执行数据库备份”“每5分钟检查服务健康状态”“订单创建后30分钟未支付自动取消”。
完整用法示例(含3类定时任务)
public class ScheduledThreadPoolDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 创建核心线程数为2的定时线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
// 2. 任务1:延迟执行(提交后3秒执行1次)
ScheduledFuture<?> delayTask = scheduledThreadPool.schedule(() -> {
System.out.printf("[延迟任务] 执行时间:%s,线程名:%s%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
Thread.currentThread().getName());
}, 3, TimeUnit.SECONDS);
// 3. 任务2:固定延迟执行(首次延迟1秒,之后间隔2秒执行,以上次结束时间为起点)
ScheduledFuture<?> fixedDelayTask = scheduledThreadPool.scheduleWithFixedDelay(() -> {
long start = System.currentTimeMillis();
System.out.printf("[固定延迟任务] 开始时间:%s,线程名:%s%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟任务耗时1秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
long end = System.currentTimeMillis();
System.out.printf("[固定延迟任务] 结束时间:%s,耗时:%dms%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
(end - start));
}, 1, 2, TimeUnit.SECONDS);
// 4. 任务3:固定频率执行(首次延迟1秒,之后间隔2秒执行,以上次开始时间为起点)
ScheduledFuture<?> fixedRateTask = scheduledThreadPool.scheduleAtFixedRate(() -> {
long start = System.currentTimeMillis();
System.out.printf("[固定频率任务] 开始时间:%s,线程名:%s%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟任务耗时1秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
long end = System.currentTimeMillis();
System.out.printf("[固定频率任务] 结束时间:%s,耗时:%dms%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
(end - start));
}, 1, 2, TimeUnit.SECONDS);
// 5. 运行5秒后,取消固定频率任务(演示任务取消)
Thread.sleep(5000);
if (!fixedRateTask.isCancelled()) {
fixedRateTask.cancel(true); // true:中断正在执行的任务
System.out.println("[固定频率任务] 已取消");
}
// 6. 避免主线程退出,让任务继续执行(实际项目中需根据业务控制线程池生命周期)
Thread.sleep(10000);
// 7. 关闭线程池(定时线程池需手动关闭,否则会一直运行)
scheduledThreadPool.shutdown();
if (!scheduledThreadPool.awaitTermination(5, TimeUnit.SECONDS)) {
scheduledThreadPool.shutdownNow();
}
System.out.println("线程池已关闭");
}
}
执行结果关键对比(固定延迟 vs 固定频率):
- 固定延迟任务:首次 1 秒后开始(如 10:00:01),耗时 1 秒(10:00:02 结束),下次执行时间为 10:00:04(结束时间 + 2 秒);
- 固定频率任务:首次 1 秒后开始(10:00:01),耗时 1 秒(10:00:02 结束),下次执行时间为 10:00:03(开始时间 + 2 秒)。
源码解析:风险与 “任务堆积” 问题
newScheduledThreadPool的源码如下:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
// ScheduledThreadPoolExecutor的父类是ThreadPoolExecutor,其构造默认参数:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
(1)核心风险:最大线程数无上限导致 OOM
与newCachedThreadPool类似,最大线程数 = Integer.MAX_VALUE,若定时任务执行时间过长(如任务间隔 2 秒,但执行耗时 3 秒),会导致线程数持续增加:
- 第 1 个任务 10:00:01 开始,10:00:04 结束(耗时 3 秒);
- 第 2 个任务本应 10:00:03 开始,但此时线程被占用,会创建新线程执行;
- 长期累积会导致线程数爆炸,触发 OOM 或 CPU 使用率飙升。
(2)隐藏问题:延迟队列的 “任务堆积”
DelayedWorkQueue的默认容量是Integer.MAX_VALUE,若大量定时任务被提交(如每秒提交 1000 个 “延迟 1 小时执行” 的任务),会导致队列中堆积大量未到执行时间的任务,占用大量堆内存,最终触发 OOM。
实战案例:某电商项目用newScheduledThreadPool(5)处理 “订单 30 分钟未支付自动取消”,大促期间每秒产生 5000 个新订单,每个订单都提交一个延迟任务,1 小时后队列堆积 1800 万 + 任务,堆内存耗尽,服务宕机。
替代方案:生产环境如何安全实现 “定时线程池”?
核心思路:限制最大线程数 + 控制延迟队列容量 + 任务合并,避免资源耗尽。示例:
// 安全的定时线程池(8核CPU场景)
ScheduledExecutorService safeScheduledThreadPool = new ScheduledThreadPoolExecutor(
5, // 核心线程数=5(根据定时任务数量调整)
new CustomThreadFactory("order-timeout"), // 自定义线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略(订单任务重要,抛异常告警)
) {
// 重写DelayedWorkQueue的构造,限制队列容量(默认无界,需自定义)
@Override
protected BlockingQueue<Runnable> createQueue() {
// 自定义延迟队列,容量限制为10000(避免堆积)
return new LimitedDelayedWorkQueue(10000);
}
};
// 自定义有界延迟队列(继承DelayedWorkQueue,重写offer方法限制容量)
class LimitedDelayedWorkQueue extends DelayedWorkQueue {
private final int capacity;
public LimitedDelayedWorkQueue(int capacity) {
this.capacity = capacity;
}
@Override
public boolean offer(Runnable e) {
// 队列满时返回false,触发拒绝策略
if (size() >= capacity) {
return false;
}
return super.offer(e);
}
}
// 额外优化:订单超时任务合并(同一用户的未支付订单,可合并为1个延迟任务)
// 避免重复提交,减少队列任务数
总结
通过对 4 种线程池的深度解析,我们可以明确 Executors 工具类的使用边界:
1. 可以使用 Executors 的场景
- Demo 开发 / 本地测试:无需关注性能和资源风险,快速验证业务逻辑(如验证多线程任务执行顺序);
- 短期一次性任务:任务量少、执行时间短,不会出现任务堆积(如数据导出脚本,执行完就关闭线程池);
- 非核心非生产环境:如内部管理系统的日志处理、数据统计,即使出现 OOM 也不会影响核心业务。
2. 必须禁用 Executors 的场景
- 生产环境核心业务:如订单处理、支付回调、用户数据同步,需避免资源耗尽风险;
- 高并发场景:任务量波动大、执行时间不确定(如秒杀、大促),易触发线程爆炸或 OOM;
- 长期运行的服务:如网关、微服务实例,线程池会持续接收任务,需严格控制资源占用。
3. 生产环境的 “黄金法则”
无论使用哪种线程池,记住 3 个核心原则:
- 拒绝无界队列:任务队列必须指定容量,避免任务堆积导致 OOM;
- 限制最大线程数:根据 CPU 核心数和任务类型,设置合理的最大线程数(如 IO 密集型 = 2*CPU 核心数,CPU 密集型 = CPU 核心数 + 1);
- 自定义线程工厂:给线程起有意义的名字,便于日志排查(如 “order-callback-thread-1”)。
最后,用一张表格汇总 4 种线程池的核心信息,方便快速查阅:
线程池类型 | 核心参数特点 | 核心风险 | 适用场景 | 生产替代方案 |
newFixedThreadPool | 核心线程数 = 最大线程数,无界队列 | 任务堆积→OOM | 任务量已知、并发固定的短期任务 | ThreadPoolExecutor + 有界队列 + 固定线程数 |
newCachedThreadPool | 核心线程数 = 0,最大线程数无上限 | 线程爆炸→OOM/CPU 100% | 任务短、量波动大的临时任务 | ThreadPoolExecutor + 限制最大线程数 |
newSingleThreadExecutor | 单线程,无界队列,线程自动恢复 | 任务堆积→OOM,无法调线程数 | 需串行执行的低并发任务 | ThreadPoolExecutor + 有界队列 + 动态线程数 |
newScheduledThreadPool | 核心线程数固定,最大线程数无上限 | 线程爆炸 + 队列堆积→OOM | 简单定时任务(非核心) |
|
掌握这些知识,你就能在实际开发中避开 Executors 的 “坑”,用更安全、更灵活的方式管理线程池,保障系统的高性能和稳定性。
相关推荐
- 高性能并发队列Disruptor使用详解
-
基本概念Disruptor是一个高性能的异步处理框架,是一个轻量的Java消息服务JMS,能够在无锁的情况下实现队列的并发操作Disruptor使用环形数组实现了类似队列的功能,并且是一个有界队列....
- Disruptor一个高性能队列_java高性能队列
-
Disruptor一个高性能队列前言说到队列比较熟悉的可能是ArrayBlockingQueue、LinkedBlockingQueue这两个有界队列,大多应用在线程池中使用能保证线程安全,但其安全性...
- 谈谈防御性编程_防御性策略
-
防御性编程对于程序员来说是一种良好的代码习惯,是为了保护自己的程序在不可未知的异常下,避免带来更大的破坏性崩溃,使得程序在错误发生时,依然能够云淡风轻的处理,但很多程序员入行很多年,写出的代码依然都是...
- 有人敲门,开水开了,电话响了,孩子哭了,你先顾谁?
-
前言哎呀,这种情况你肯定遇到过吧!正在家里忙活着,突然——咚咚咚有人敲门,咕噜咕噜开水开了,铃铃铃电话响了,哇哇哇孩子又哭了...我去,四件事一起来,人都懵了!你说先搞哪个?其实这跟我们写Java多线...
- 面试官:线程池如何按照core、max、queue的执行顺序去执行?
-
前言这是一个真实的面试题。前几天一个朋友在群里分享了他刚刚面试候选者时问的问题:"线程池如何按照core、max、queue的执行循序去执行?"。我们都知道线程池中代码执行顺序是:co...
- 深入剖析 Java 中线程池的多种实现方式
-
在当今高度并发的互联网软件开发领域,高效地管理和利用线程资源是提升程序性能的关键。Java作为一种广泛应用于后端开发的编程语言,为我们提供了丰富的线程池实现方式。今天,就让我们深入探讨Java中...
- 并发编程之《彻底搞懂Java线程》_java多线程并发解决方案详解
-
目录引言一、核心概念:线程是什么?...
- Redis怎么实现延时消息_redis实现延时任务
-
一句话总结Redis可通过有序集合(ZSET)实现延时消息:将消息作为value,到期时间戳作为score存入ZSET。消费者轮询用ZRANGEBYSCORE获取到期消息,配合Lua脚本保证原子性获取...
- CompletableFuture真的用对了吗?盘点它最容易被误用的5个场景
-
在Java并发编程中,CompletableFuture是处理异步任务的利器,但不少开发者在使用时踩过这些坑——线上服务突然雪崩、异常悄无声息消失、接口响应时间翻倍……本文结合真实案例,拆解5个最容易...
- 接口性能优化技巧,有点硬_接口性能瓶颈
-
背景我负责的系统到2021年初完成了功能上的建设,开始进入到推广阶段。随着推广的逐步深入,收到了很多好评的同时也收到了很多对性能的吐槽。刚刚收到吐槽的时候,我们的心情是这样的:...
- 禁止使用这5个Java类,每一个背后都有一段"血泪史"
-
某电商平台的支付系统突然报警:大量订单状态异常。排查日志发现,同一笔订单被重复支付了三次。事后复盘显示,罪魁祸首竟是一行看似无害的SimpleDateFormat代码。在Java开发中,这类因使用不安...
- 无锁队列Disruptor原理解析_无锁队列实现原理
-
队列比较队列...
- Java并发队列与容器_java 并发队列
-
【前言:无论是大数据从业人员还是Java从业人员,掌握Java高并发和多线程是必备技能之一。本文主要阐述Java并发包下的阻塞队列和并发容器,其实研读过大数据相关技术如Spark、Storm等源码的,...
- 线程池工具及拒绝策略的使用_线程池处理策略
-
线程池的拒绝策略若线程池中的核心线程数被用完且阻塞队列已排满,则此时线程池的资源已耗尽,线程池将没有足够的线程资源执行新的任务。为了保证操作系统的安全,线程池将通过拒绝策略处理新添加的线程任务。...
- 【面试题精讲】ArrayBlockingQueue 和 LinkedBlockingQueue 区别?
-
有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
程序员的开源月刊《HelloGitHub》第 71 期
-
详细介绍一下Redis的Watch机制,可以利用Watch机制来做什么?
-
假如有100W个用户抢一张票,除了负载均衡办法,怎么支持高并发?
-
如何将AI助手接入微信(打开ai手机助手)
-
Java面试必考问题:什么是乐观锁与悲观锁
-
SparkSQL——DataFrame的创建与使用
-
redission YYDS spring boot redission 使用
-
一文带你了解Redis与Memcached? redis与memcached的区别
-
如何利用Redis进行事务处理呢? 如何利用redis进行事务处理呢英文
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)