浅谈Java线程池完全指南
一、为什么需要线程池?
在并发编程中,线程是宝贵的系统资源。频繁创建和销毁线程会带来严重的性能开销:
- 创建开销:每次创建线程都需要分配内存、初始化栈空间
- 调度开销:大量线程会导致 CPU 上下文频繁切换
- 资源耗尽:无限制创建线程可能导致 OOM(OutOfMemoryError)
💡 核心思想:线程池通过复用已有线程来减少创建销毁的开销,同时控制最大并发数防止资源耗尽。
二、ThreadPoolExecutor 核心参数
Java线程池的本质是 ThreadPoolExecutor 类,它有7个核心参数:
public ThreadPoolExecutor(
int corePoolSize, // 1. 核心线程数(常驻线程)
int maximumPoolSize, // 2. 最大线程数
long keepAliveTime, // 3. 非核心线程空闲存活时间
TimeUnit unit, // 4. 存活时间单位
BlockingQueue<Runnable> workQueue, // 5. 任务队列
ThreadFactory threadFactory, // 6. 线程工厂
RejectedExecutionHandler handler // 7. 拒绝策略
)
参数详解
| 参数 | 说明 | 推荐值 |
|---|---|---|
| corePoolSize | 即使空闲也不会被回收的线程数 | CPU密集型:CPU核数+1;IO密集型:CPU核数×2 |
| maximumPoolSize | 线程池允许的最大线程数 | 根据任务类型和硬件配置调整 |
| keepAliveTime | 非核心线程闲置超时时间 | 通常30秒~60秒 |
| workQueue | 存放等待执行任务的队列 | 见下文队列选择 |
| threadFactory | 创建新线程的工厂 | 推荐使用自定义工厂设置有意义的线程名 |
| handler | 队列满且线程数达上限时的处理策略 | 见下文拒绝策略 |
📌 任务队列的选择
| 队列类型 | 特点 | 适用场景 |
|---|---|---|
| ArrayBlockingQueue | 有界数组队列,FIFO | 有明确容量限制的场景 |
| LinkedBlockingQueue | 可选有界/无界链表队列 | 默认用于Executors工厂方法 |
| SynchronousQueue | 不存储元素,直接传递 | CachedThreadPool使用 |
| PriorityBlockingQueue | 支持优先级排序 | 需要优先处理高优先级任务 |
📌 四种拒绝策略
| 策略 | 行为 |
|---|---|
| AbortPolicy(默认) | 抛出 RejectedExecutionException |
| CallerRunsPolicy | 由提交任务的线程自己执行 |
| DiscardPolicy | 静默丢弃任务,不抛异常 |
| DiscardOldestPolicy | 丢弃队列中最老的任务 |
三、线程池工作流程
当提交一个新任务到线程池时,执行流程如下:
提交任务
│
┌──────────▼──────────┐
│ 当前线程 < corePoolSize? │
└────┬─────────┬────┘
是│ │否
▼ │
创建核心线程 │
执行任务 │
▼
┌──────────────────┐
│ 工作队列未满? │
└───┬──────────┬───┘
是│ │否
▼ │
加入等待队列 │
▼
┌──────────────────┐
│ 当前线程 < maxPoolSize? │
└───┬──────────┬───┘
是│ │否
▼ │
创建非核心线程 │
执行任务 │
▼
执行拒绝策略关键规则总结:
- 优先用核心线程执行任务
- 核心线程满了进队列
- 队列满了创建非核心线程
- 非核心线程也满了 → 拒绝策略
四、三种常用线程池
1. FixedThreadPool — 固定大小线程池
// 固定10个线程的线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(10);
// 等价于:
ExecutorService fixedPool = new ThreadPoolExecutor(
10, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()
);
✅ 适用场景:Web服务器处理请求、批量数据处理
⚠️ 注意:队列无界可能导致OOM
2. CachedThreadPool — 可缓存线程池
// 按需创建线程,空闲60秒回收
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 等价于:
ExecutorService cachedPool = new ThreadPoolExecutor(
0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>()
);
✅ 适用场景:短时异步任务、负载不均衡场景
⚠️ 注意:最大线程数为Integer.MAX_VALUE,可能创建过多线程
3. SingleThreadExecutor — 单线程线程池
// 只有一个线程的线程池,保证任务顺序执行
ExecutorService singlePool = Executors.newSingleThreadExecutor();
// 等价于:
ExecutorService singlePool = new ThreadPoolExecutor(
1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()
);
✅ 适用场景:需要保证任务按顺序执行的场景
⚠️ 注意:队列无界,堆积任务可能导致OOM
⚠️ 重要提醒:阿里巴巴《Java开发手册》明确要求禁止使用Executors创建线程池,因为默认的无界队列可能导致OOM。推荐通过 ThreadPoolExecutor 自定义参数。
五、实战示例:正确创建和使用线程池
✅ 推荐写法
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1. 自定义线程工厂(设置有意义的线程名)
ThreadFactory namedFactory = new ThreadFactory() {
private final AtomicInteger counter = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("my-pool-thread-" + counter.incrementAndGet());
t.setDaemon(false); // 非守护线程
return t;
}
};
// 2. 创建线程池(推荐方式)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // corePoolSize: 核心线程数
8, // maximumPoolSize: 最大线程数
60L, // keepAliveTime: 空闲存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(100), // 有界队列,容量100
namedFactory, // 自定义线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:调用者执行
);
// 3. 提交任务
for (int i = 0; i < 20; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println(Thread.currentThread().getName()
+ " 正在执行任务 " + taskId);
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName()
+ " 完成任务 " + taskId);
});
}
// 4. 优雅关闭
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 超时后强制关闭
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
使用 submit() 获取返回值
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<String> future = executor.submit(() -> {
// 执行耗时计算
Thread.sleep(2000);
return "计算结果";
});
// 获取结果(阻塞直到完成)
String result = future.get(); // 或 future.get(3, TimeUnit.SECONDS)
System.out.println(result);
executor.shutdown();
六、线程池监控与调优
监控关键指标
ThreadPoolExecutor executor = ...;
// 核心监控指标
System.out.println("当前活跃线程数: " + executor.getActiveCount());
System.out.println("当前线程总数: " + executor.getPoolSize());
System.out.println("已完成任务数: " + executor.getCompletedTaskCount());
System.out.println("排队中任务数: " + executor.getQueue().size());
System.out.println("历史最大线程数: " + executor.getLargestPoolSize());
🔧 调优建议
| 场景 | corePoolSize 建议 | maximumPoolSize 建议 | 队列选择 |
|---|---|---|---|
| CPU 密集型(计算) | CPU 核数 + 1 | CPU 核数 + 1 | 小容量有界队列 |
| IO 密集型(网络/DB) | CPU 核数 × 2 | CPU 核数 × 2 ~ 4 | 较大容量有界队列 |
| 混合型 | 按比例分配 | 动态扩容 | 有界队列 + 合理拒绝策略 |
七、常见问题与最佳实践
❌ 常见错误
- 使用 Executors 创建线程池 → 可能导致 OOM
- 线程池不复用 → 每次 new 新线程池,浪费资源
- 忘记 shutdown() → JVM 无法正常退出
- 任务中吞掉 InterruptedException → 应恢复中断状态
- 使用无界队列 → 内存可能无限增长
✅ 最佳实践清单
- 始终通过 ThreadPoolExecutor 构造函数创建线程池
- 给线程设置有意义的名称(便于排查问题)
- 使用有界队列(防止内存溢出)
- 指定合理的拒绝策略
- 记得调用 shutdown() 或 shutdownNow()
- 捕获并处理 RejectedExecutionException
- 对长时间运行的任务设置超时
八、总结
| 要点 | 内容 |
|---|---|
| 核心优势 | 线程复用、控制并发、统一管理 |
| 7个参数 | core / max / keepAlive / unit / queue / factory / handler |
| 执行流程 | 核心线程 → 队列 → 非核心线程 → 拒绝策略 |
| 三种常用池 | Fixed / Cached / Single(生产慎用) |
| 最佳实践 | 自定义 ThreadPoolExecutor + 有界队列 + 合理拒绝策略 |
📚 延伸阅读:建议阅读 Doug Lea 的《Concurrent Programming in Java》以及 JDK 源码中
java.util.concurrent包的实现。
本文基于 JDK 8+ 编写,涵盖了线程池的核心概念与实战用法。
九、完整可运行测试代码
以下是一个完整、可直接编译运行的 Java 线程池测试程序,涵盖了本文所有核心知识点。
文件结构
ThreadPoolDemo/ ├── src/ │ └── main/ │ └── java/ │ └── com/ │ └── example/ │ ├── ThreadPoolTest.java # 主测试类 │ ├── NamedThreadFactory.java # 自定义线程工厂 │ └── MonitorTask.java # 监控任务 └── pom.xml # Maven依赖(JDK 8+)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>thread-pool-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- 可执行 JAR 插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.ThreadPoolTest</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- 打包依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>NamedThreadFactory.java — 自定义线程工厂
package com.example;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义线程工厂:为每个线程设置有意义的名称,便于排查问题
*
* 使用方式:
* ThreadFactory factory = new NamedThreadFactory("my-worker");
* ExecutorService pool = new ThreadPoolExecutor(..., factory, ...);
*/
public class NamedThreadFactory implements ThreadFactory {
private final String prefix; // 线程名前缀
private final AtomicInteger counter = new AtomicInteger(1); // 线程计数器
private final boolean daemon; // 是否守护线程
public NamedThreadFactory(String prefix) {
this(prefix, false);
}
public NamedThreadFactory(String prefix, boolean daemon) {
this.prefix = prefix;
this.daemon = daemon;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, prefix + "-" + counter.getAndIncrement());
t.setDaemon(daemon);
// 设置未捕获异常处理器
t.setUncaughtExceptionHandler((thread, ex) -> {
System.err.println("[" + thread.getName() "] 未捕获异常: " + ex.getMessage());
ex.printStackTrace();
});
return t;
}
}
MonitorTask.java — 定时监控任务
package com.example;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 线程池监控任务:定期打印线程池运行状态
*/
public class MonitorTask implements Runnable {
private final ThreadPoolExecutor executor;
private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
public MonitorTask(ThreadPoolExecutor executor) {
this.executor = executor;
}
@Override
public void run() {
System.out.println("\n========== 线程池监控 [" + sdf.format(new Date()) + "] ==========");
System.out.printf(" 核心线程数: %d / 最大线程数: %d%n",
executor.getCorePoolSize(), executor.getMaximumPoolSize());
System.out.printf(" 当前活跃线程: %d | 当前总线程: %d | 历史峰值: %d%n",
executor.getActiveCount(), executor.getPoolSize(), executor.getLargestPoolSize());
System.out.printf(" 已完成任务: %d | 总提交任务: %d%n",
executor.getCompletedTaskCount(), executor.getTaskCount());
System.out.printf(" 队列中等待: %d (剩余容量: %d)%n",
executor.getQueue().size(), executor.getQueue().remainingCapacity());
System.out.println("========================================================\n");
}
/**
* 启动定时监控(每5秒打印一次状态)
*/
public static void startMonitoring(ThreadPoolExecutor executor) {
ScheduledMonitor monitor = new ScheduledMonitor(executor);
monitor.start();
}
/**
* 内部定时器实现(使用单独的守护线程)
*/
static class ScheduledMonitor {
private final ThreadPoolExecutor target;
private volatile boolean running = true;
ScheduledMonitor(ThreadPoolExecutor target) {
this.target = target;
}
void start() {
Thread monitorThread = new Thread(() -> {
while (running && !target.isTerminated()) {
try {
new MonitorTask(target).run();
Thread.sleep(5000); // 每5秒监控一次
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println(">>> 监控线程已停止");
}, "pool-monitor");
monitorThread.setDaemon(true);
monitorThread.start();
}
void stop() {
running = false;
}
}
}
ThreadPoolTest.java — 主测试类(完整可运行)
package com.example;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.List;
import java.util.ArrayList;
/**
* ============================================================
* Java线程池完整测试程序
* ============================================================
*
* 本程序演示了以下内容:
* 1. 自定义ThreadPoolExecutor创建线程池
* 2. 核心参数配置(core/max/queue/factory/handler)
* 3. submit() 返回Future获取结果
* 4. 四种拒绝策略对比
* 5. 线程池监控
* 6. 优雅关闭(shutdown + awaitTermination)
*
* 运行方式:
* mvn clean compile exec:java -Dexec.mainClass="com.example.ThreadPoolTest"
* 或直接运行 main 方法
*
* 预期输出:
* 各任务由不同工作线程执行,最后打印汇总统计信息
* ============================================================
*/
public class ThreadPoolTest {
// ========== 任务计数器 ==========
private static final AtomicInteger successCount = new AtomicInteger(0);
private static final AtomicInteger failCount = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
System.out.println("╔══════════════════════════════════════════╗");
System.out.println("║ Java线程池完整测试程序 v1.0 ║");
System.out.println("╚══════════════════════════════════════════╝\n");
// ==================== 第一步:创建线程池 ====================
System.out.println(">>> 第一步:创建自定义线程池...");
ThreadPoolExecutor executor = createThreadPool();
// 启动监控
MonitorTask.startMonitoring(executor);
// ==================== 第二步:测试submit返回值 ====================
System.out.println(">>> 第二步:测试submit()获取Future返回值...");
testSubmitWithFuture(executor);
// ==================== 第三步:批量提交任务 ====================
System.out.println("\n>>> 第三步:批量提交30个模拟任务...");
batchSubmitTasks(executor, 30);
// ==================== 第四步:测试拒绝策略 ====================
System.out.println("\n>>> 第四步:演示拒绝策略...");
testRejectionPolicy();
// ==================== 第五步:优雅关闭 ====================
System.out.println("\n>>> 第五步:优雅关闭线程池...");
gracefulShutdown(executor);
// ==================== 最终统计 ====================
printFinalStats();
}
/**
* 创建自定义线程池(推荐的生产环境写法)
*/
private static ThreadPoolExecutor createThreadPool() {
int coreSize = 4; // 核心线程数
int maxSize = 8; // 最大线程数
int queueCapacity = 50; // 队列容量
ThreadPoolExecutor pool = new ThreadPoolExecutor(
coreSize,
maxSize,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(queueCapacity),
new NamedThreadFactory("worker"), // 自定义线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:调用者执行
);
// 允许核心线程超时回收(可选)
pool.allowCoreThreadTimeOut(false);
System.out.printf(" ✓ 线程池创建成功: core=%d, max=%d, queue=%d%n",
coreSize, maxSize, queueCapacity);
return pool;
}
/**
* 测试submit()方法获取Future返回值
*/
private static void testSubmitWithFuture(ThreadPoolExecutor executor) throws Exception {
Callable<String> task1 = () -> {
Thread.sleep(800);
return "Hello from Future!";
};
Callable<Integer> task2 = () -> {
Thread.sleep(500);
return 42;
};
Callable<List<String>> task3 = () -> {
Thread.sleep(300);
List<String> list = new ArrayList<>();
list.add("Java");
list.add("ThreadPool");
list.add("Demo");
return list;
};
// 提交任务并获取Future
Future<String> f1 = executor.submit(task1);
Future<Integer> f2 = executor.submit(task2);
Future<List<String>> f3 = executor.submit(task3);
// 获取结果(阻塞等待)
System.out.println(" Future[1] 结果: " + f1.get()); // Hello from Future!
System.out.println(" Future[2] 结果: " + f2.get()); // 42
System.out.println(" Future[3] 结果: " + f3.get()); // [Java, ThreadPool, Demo]
System.out.println(" ✓ Future测试完成\n");
}
/**
* 批量提交模拟任务
*/
private static void batchSubmitTasks(ThreadPoolExecutor executor, int count)
throws InterruptedException {
CountDownLatch latch = new CountDownLatch(count);
long startTime = System.currentTimeMillis();
for (int i = 1; i <= count; i++) {
final int taskId = i;
executor.execute(() -> {
try {
// 模拟耗时操作(IO密集型:随机200~1000ms)
int sleepMs = 200 + (int)(Math.random() * 800);
Thread.sleep(sleepMs);
String threadName = Thread.currentThread().getName();
System.out.printf(" [%s] ✅ 任务#%d 完成 (耗时%dms)%n",
threadName, taskId, sleepMs);
successCount.incrementAndGet();
} catch (InterruptedException e) {
System.out.printf(" [任务#%d] ❌ 被中断%n", taskId);
failCount.incrementAndGet();
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // 计数器减1
}
});
}
// 等待所有任务完成(最多等60秒)
boolean allDone = latch.await(60, TimeUnit.SECONDS);
long elapsed = System.currentTimeMillis() - startTime;
System.out.printf(" ✓ 所有任务完成? %s | 总耗时: %dms | 成功: %d | 失败: %d%n",
allDone ? "是" : "超时", elapsed,
successCount.get(), failCount.get());
}
/**
* 演示四种拒绝策略的行为差异
*/
private static void testRejectionPolicy() {
System.out.println(" --- 创建一个极小线程池来触发拒绝策略 ---");
// 极小配置:1核心线程,队列容量2,最大线程2
ThreadPoolExecutor tinyPool = new ThreadPoolExecutor(
1, 2,
10L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2),
new NamedThreadFactory("reject-test"),
new ThreadPoolExecutor.AbortPolicy() // 默认:抛异常
);
try {
// 提交5个任务(1执行 + 2排队 + 2非核心 = 5刚好满)
for (int i = 1; i <= 5; i++) {
final int id = i;
tinyPool.execute(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(" [reject-test] 任务#" + id + " 完成");
});
}
System.out.println(" ✓ 前5个任务正常提交");
// 第6个任务应该触发拒绝策略
try {
tinyPool.execute(() -> System.out.println("不该执行到这里"));
} catch (RejectedExecutionException e) {
System.out.println(" ✓ 第6个任务被拒绝! (AbortPolicy抛出异常)");
}
} finally {
tinyPool.shutdownNow();
}
System.out.println(" ✓ 拒绝策略测试完成\n");
}
/**
* 优雅关闭线程池(两阶段关闭)
*/
private static void gracefulShutdown(ThreadPoolExecutor executor) throws InterruptedException {
// 阶段1:停止接受新任务,等待已有任务完成
executor.shutdown();
// 阶段2:最多等待30秒
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
// 超时后强制关闭
System.out.println(" ⚠ 线程池未在30秒内关闭,执行shutdownNow()...");
List<Runnable> unfinished = executor.shutdownNow();
System.out.println(" 强制中断了 " + unfinished.size() + " 个未完成任务");
}
System.out.printf(" ✓ 线程池已关闭 (isTerminated=%b, isShutdown=%b)%n",
executor.isTerminated(), executor.isShutdown());
}
/**
* 打印最终统计信息
*/
private static void printFinalStats() {
System.out.println("\n╔══════════════════════════════════════════╗");
System.out.println("║ 测试执行报告 ║");
System.out.println("╠══════════════════════════════════════════╣");
System.out.printf("║ 成功完成任务: %-24d ║%n", successCount.get());
System.out.printf("║ 失败/中断任务: %-23d ║%n", failCount.get());
System.out.printf("║ 总计: %-33d ║%n", successCount.get() + failCount.get());
System.out.println("╚══════════════════════════════════════════╝");
System.out.println("\n🎉 测试全部完成!");
}
}
运行步骤
# 1. 克隆或创建项目目录 mkdir -p ThreadPoolDemo/src/main/java/com/example cd ThreadPoolDemo # 2. 将上述4个文件放入对应路径 # 3. 编译并运行 mvn clean compile exec:java -Dexec.mainClass="com.example.ThreadPoolTest" # 或者打包成可执行JAR mvn clean package java -jar target/thread-pool-demo-1.0-SNAPSHOT.jar
预期输出示例
╔══════════════════════════════════════════╗
║ Java线程池完整测试程序 v1.0 ║
╚══════════════════════════════════════════╝
>>> 第一步:创建自定义线程池...
✓ 线程池创建成功: core=4, max=8, queue=50
>>> 第二步:测试submit()获取Future返回值...
Future[1] 结果: Hello from Future!
Future[2] 结果: 42
Future[3] 结果: [Java, ThreadPool, Demo]
✓ Future测试完成
>>> 第三步:批量提交30个模拟任务...
[worker-1] ✅ 任务#1 完成 (耗时653ms)
[worker-2] ✅ 任务#2 完成 (耗时412ms)
...
✓ 所有任务完成? 是 | 总耗时: 3210ms | 成功: 30 | 失败: 0
>>> 第四步:演示拒绝策略...
✓ 前5个任务正常提交
✓ 第6个任务被拒绝! (AbortPolicy抛出异常)
>>> 第五步:优雅关闭线程池...
✓ 线程池已关闭 (isTerminated=true, isShutdown=true)
╔══════════════════════════════════════════╗
║ 测试执行报告 ║
╠══════════════════════════════════════════╣
║ 成功完成任务: 30 ║
║ 失败/中断任务: 0 ║
║ 总计: 30 ║
╚══════════════════════════════════════════╝
🎉 测试全部完成!到此这篇关于浅谈Java线程池完全指南的文章就介绍到这了,更多相关Java线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
如何将java -jar启动的服务设置为systemd服务管理方式
本文详细介绍了如何将Java应用程序配置为由systemd管理的服务,包括创建和配置.service文件的步骤,以及如何启动、停止和查看服务状态2025-01-01
Java中String、StringBuffer和StringBuilder底层实现深入剖析
在Java编程语言中String、StringBuffer和StringBuilder都是用来处理字符串的类,但它们之间存在显著的性能和功能差异,这篇文章主要介绍了Java中String、StringBuffer和StringBuilder底层实现的相关资料,需要的朋友可以参考下2026-01-01
SpringBoot如何读取xml配置bean(@ImportResource)
这篇文章主要介绍了SpringBoot如何读取xml配置bean(@ImportResource),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-01-01


最新评论