1. Java线程基础与创建方式
Java多线程编程是现代软件开发的核心技能之一。作为一名有十年Java开发经验的工程师,我经常看到新手在入门多线程时遇到各种问题。今天我们就从最基础的线程创建开始,深入探讨Java线程的方方面面。
1.1 继承Thread类方式
继承Thread类是最直观的线程创建方式,适合简单的线程场景。下面是一个完整的示例:
java复制class PrintThread extends Thread {
private final String message;
public PrintThread(String message) {
this.message = message;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(message + " " + i);
try {
Thread.sleep(500); // 模拟耗时操作
} catch (InterruptedException e) {
System.out.println("线程被中断");
Thread.currentThread().interrupt();
break;
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
PrintThread thread1 = new PrintThread("线程A");
PrintThread thread2 = new PrintThread("线程B");
thread1.start();
thread2.start();
}
}
关键点解析:
- 必须重写run()方法,这是线程执行的入口
- 通过start()方法启动线程,而不是直接调用run()
- 构造方法可以传递参数,实现线程定制化
- 需要处理InterruptedException,这是良好线程实践的基础
注意:在实际项目中,继承Thread类的方式通常只用于非常简单的场景,因为它限制了类的继承体系。
1.2 实现Runnable接口方式
实现Runnable接口是更推荐的线程创建方式,它具有更好的灵活性:
java复制class DataProcessor implements Runnable {
private final String dataSource;
public DataProcessor(String source) {
this.dataSource = source;
}
@Override
public void run() {
System.out.println("开始处理数据源: " + dataSource);
// 模拟数据处理
for (int i = 1; i <= 3; i++) {
System.out.println("处理进度: " + i + "/3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("数据处理被中断");
return;
}
}
System.out.println("数据处理完成: " + dataSource);
}
}
public class RunnableDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new DataProcessor("DB1"));
Thread t2 = new Thread(new DataProcessor("API"));
t1.start();
t2.start();
}
}
优势分析:
- 避免了Java单继承的限制
- 更适合线程池管理等高级场景
- 任务与执行线程分离,职责更清晰
- 可以方便地复用Runnable实现
1.3 Lambda表达式简化
Java 8之后,我们可以用Lambda表达式进一步简化线程创建:
java复制public class LambdaThread {
public static void main(String[] args) {
// 基本形式
new Thread(() -> {
System.out.println("Lambda线程运行中");
}).start();
// 带参数的复杂形式
new Thread(() -> processData("param1", 1000)).start();
}
private static void processData(String param, int timeout) {
System.out.println("处理参数: " + param);
try {
Thread.sleep(timeout);
System.out.println("处理完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
适用场景:
- 简单的临时性任务
- 不需要复用线程逻辑的场景
- 快速原型开发
- 测试代码
2. 线程启动与执行机制
2.1 start() vs run()的本质区别
很多初学者容易混淆start()和run()方法,这里通过实例说明它们的本质区别:
java复制public class StartVsRun {
public static void main(String[] args) {
System.out.println("主线程ID: " + Thread.currentThread().getId());
Thread thread = new Thread(() -> {
System.out.println("执行线程ID: " + Thread.currentThread().getId());
System.out.println("执行线程名称: " + Thread.currentThread().getName());
});
System.out.println("--- 直接调用run() ---");
thread.run(); // 在主线程中执行
System.out.println("--- 调用start() ---");
thread.start(); // 在新线程中执行
}
}
输出分析:
code复制主线程ID: 1
--- 直接调用run() ---
执行线程ID: 1
执行线程名称: main
--- 调用start() ---
执行线程ID: 12
执行线程名称: Thread-0
关键结论:
- start()会创建新的调用栈和线程上下文
- run()只是普通方法调用,不会创建新线程
- 多次调用start()会抛出IllegalThreadStateException
2.2 线程调度与优先级
Java线程调度依赖于操作系统,但我们可以通过优先级影响调度:
java复制public class PriorityDemo {
public static void main(String[] args) {
Thread low = new Thread(new Task("低优先级"));
Thread high = new Thread(new Task("高优先级"));
low.setPriority(Thread.MIN_PRIORITY); // 1
high.setPriority(Thread.MAX_PRIORITY); // 10
low.start();
high.start();
}
static class Task implements Runnable {
private final String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + ": " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}
优先级注意事项:
- 优先级只是提示,不保证执行顺序
- 不同操作系统对优先级的处理可能不同
- 过度依赖优先级可能导致线程饥饿
- 通常建议使用默认优先级(NORM_PRIORITY=5)
3. 线程终止与中断机制
3.1 自然终止与强制终止
自然终止示例:
java复制public class NaturalTermination {
public static void main(String[] args) {
Thread worker = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("处理任务 " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("提前终止");
return;
}
}
System.out.println("所有任务完成");
});
worker.start();
}
}
强制终止的危险性:
java复制// 危险示例 - 不要在生产环境使用
Thread thread = new Thread(() -> {
while (true) {
// 无限循环
}
});
thread.start();
// 3秒后强制终止
Thread.sleep(3000);
thread.stop(); // 已废弃方法
警告:stop()方法会立即终止线程并释放所有锁,可能导致对象状态不一致。绝对不要在生产代码中使用。
3.2 优雅的中断机制
正确的线程终止方式是通过中断机制:
java复制public class GracefulInterrupt {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("工作中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("收到中断请求");
Thread.currentThread().interrupt(); // 重新设置中断状态
}
}
System.out.println("清理资源并退出");
});
worker.start();
Thread.sleep(3500); // 让worker运行3.5秒
worker.interrupt(); // 发送中断请求
worker.join(); // 等待worker结束
System.out.println("主线程结束");
}
}
中断机制要点:
- interrupt()只是设置标志位,不会强制停止线程
- 线程需要定期检查中断状态(isInterrupted())
- 阻塞方法(sleep/wait等)会抛出InterruptedException
- 捕获异常后应恢复中断状态
3.3 使用volatile标志位
对于长时间运行的任务,可以使用volatile标志位:
java复制public class FlagShutdown {
private volatile boolean running = true;
public void shutdown() {
running = false;
}
public void work() {
new Thread(() -> {
while (running) {
System.out.println("处理业务...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("睡眠被打断");
}
}
System.out.println("优雅关闭");
}).start();
}
public static void main(String[] args) throws InterruptedException {
FlagShutdown example = new FlagShutdown();
example.work();
Thread.sleep(3500);
example.shutdown();
}
}
volatile关键作用:
- 保证多线程间的可见性
- 防止指令重排序
- 比synchronized更轻量级
4. 线程休眠与状态控制
4.1 sleep()方法详解
Thread.sleep()是控制线程执行节奏的重要方法:
java复制public class SleepDemo {
public static void main(String[] args) {
new Thread(() -> {
System.out.println("任务开始: " + new Date());
try {
TimeUnit.SECONDS.sleep(2); // 更可读的写法
} catch (InterruptedException e) {
System.out.println("睡眠被打断");
Thread.currentThread().interrupt();
}
System.out.println("任务结束: " + new Date());
}).start();
}
}
sleep()特点:
- 让出CPU但不释放锁
- 睡眠时间是最小时间,不保证精确
- 可被中断,抛出InterruptedException
- 使用TimeUnit枚举可提高可读性
4.2 sleep()与yield()比较
java复制public class SleepVsYield {
public static void main(String[] args) {
Runnable task = () -> {
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
// Thread.yield(); // 情况1
// try { Thread.sleep(10); } catch (InterruptedException e) {} // 情况2
}
};
new Thread(task, "线程A").start();
new Thread(task, "线程B").start();
}
}
对比分析:
| 特性 | sleep() | yield() |
|---|---|---|
| 是否指定时间 | 是 | 否 |
| 是否保证暂停 | 是 | 否(只是提示) |
| 线程状态变化 | TIMED_WAITING | RUNNABLE |
| 是否保持锁 | 是 | 是 |
| 适用场景 | 固定延迟 | 提高响应性 |
4.3 精确延时技巧
对于需要精确延时的场景,可以使用以下模式:
java复制public class PreciseDelay {
public static void preciseSleep(long millis) throws InterruptedException {
long endTime = System.currentTimeMillis() + millis;
long remaining = millis;
while (remaining > 0) {
Thread.sleep(remaining);
remaining = endTime - System.currentTimeMillis();
}
}
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
preciseSleep(2000);
long elapsed = System.currentTimeMillis() - start;
System.out.println("实际休眠时间: " + elapsed + "ms");
}
}
适用场景:
- 定时任务执行
- 游戏循环
- 实时系统
- 性能测试
5. 线程状态与生命周期
5.1 完整状态转换图
Java线程的生命周期包含6种状态:
- NEW - 新建状态
- RUNNABLE - 可运行状态
- BLOCKED - 阻塞状态
- WAITING - 无限等待状态
- TIMED_WAITING - 限时等待状态
- TERMINATED - 终止状态
5.2 状态检测与监控
通过getState()方法可以获取线程当前状态:
java复制public class ThreadStateDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000);
synchronized (ThreadStateDemo.class) {
ThreadStateDemo.class.wait();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
System.out.println("创建后: " + thread.getState()); // NEW
thread.start();
System.out.println("启动后: " + thread.getState()); // RUNNABLE
Thread.sleep(100);
System.out.println("休眠中: " + thread.getState()); // TIMED_WAITING
Thread.sleep(2000);
System.out.println("等待中: " + thread.getState()); // WAITING
synchronized (ThreadStateDemo.class) {
ThreadStateDemo.class.notify();
}
thread.join();
System.out.println("终止后: " + thread.getState()); // TERMINATED
}
}
5.3 状态转换触发条件
| 状态转换 | 触发条件 |
|---|---|
| NEW → RUNNABLE | start()方法调用 |
| RUNNABLE → BLOCKED | 竞争同步锁失败 |
| RUNNABLE → WAITING | wait()/join()调用 |
| RUNNABLE → TIMED_WAITING | sleep()/带超时的wait() |
| WAITING/TIMED_WAITING → RUNNABLE | 通知/超时/中断 |
| RUNNABLE → TERMINATED | run()方法结束 |
6. 实战经验与最佳实践
6.1 线程命名规范
良好的线程命名有助于问题诊断:
java复制public class ThreadNaming {
public static void main(String[] args) {
Thread worker1 = new Thread(new Task(), "Worker-1");
Thread worker2 = new Thread(new Task(), "Worker-2");
worker1.start();
worker2.start();
}
static class Task implements Runnable {
@Override
public void run() {
System.out.println("当前线程: " + Thread.currentThread().getName());
// 业务逻辑...
}
}
}
命名建议:
- 使用有意义的名称
- 包含功能或角色信息
- 必要时加入序号
- 保持一致性
6.2 异常处理策略
未捕获的异常会导致线程终止:
java复制public class ThreadException {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
throw new RuntimeException("测试异常");
});
thread.setUncaughtExceptionHandler((t, e) -> {
System.out.println("线程 " + t.getName() + " 抛出异常: " + e);
});
thread.start();
}
}
异常处理建议:
- 始终在run()方法内捕获异常
- 设置UncaughtExceptionHandler
- 记录完整的异常堆栈
- 考虑异常后的资源清理
6.3 资源清理模式
确保线程退出时释放资源:
java复制public class ResourceCleanup {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
try {
// 获取资源
System.out.println("获取数据库连接");
// 模拟工作
while (!Thread.currentThread().isInterrupted()) {
System.out.println("处理数据...");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 确保资源释放
System.out.println("释放数据库连接");
}
});
worker.start();
Thread.sleep(3500);
worker.interrupt();
worker.join();
}
}
6.4 性能考量与陷阱
常见性能陷阱:
- 过度创建线程(考虑使用线程池)
- 频繁的线程上下文切换
- 不合理的锁竞争
- 未限制的队列增长
优化建议:
- 使用线程池管理线程生命周期
- 减少同步块的范围
- 考虑使用并发集合
- 监控线程状态和数量
7. 常见问题排查
7.1 线程不执行问题
可能原因:
- 忘记调用start()方法
- 线程优先级设置过低
- 资源竞争导致死锁
- 异常导致线程提前退出
排查步骤:
- 检查线程状态(getState())
- 查看是否有未捕获异常
- 检查CPU和内存使用情况
- 使用jstack分析线程堆栈
7.2 线程挂起问题
诊断方法:
java复制public class ThreadDiagnosis {
public static void main(String[] args) {
Thread problematicThread = new Thread(() -> {
// 疑似挂起的代码
});
problematicThread.start();
// 监控线程状态
new Timer(true).schedule(new TimerTask() {
@Override
public void run() {
System.out.println("线程状态: " + problematicThread.getState());
}
}, 0, 1000);
}
}
7.3 内存泄漏问题
线程相关的内存泄漏通常由于:
- 线程池未正确关闭
- 持有对象引用导致无法GC
- 线程局部变量未清理
- 监听器未正确注销
诊断工具:
- jvisualvm
- MAT内存分析工具
- jmap堆转储分析
8. 高级技巧与模式
8.1 线程局部变量
ThreadLocal的使用模式:
java复制public class ThreadLocalDemo {
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static void main(String[] args) {
Runnable task = () -> {
System.out.println(dateFormatHolder.get().format(new Date()));
};
new Thread(task).start();
new Thread(task).start();
}
}
使用场景:
- 线程安全的日期格式化
- 用户会话信息存储
- 数据库连接管理
- 避免方法参数传递
8.2 守护线程应用
守护线程示例:
java复制public class DaemonThread {
public static void main(String[] args) {
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("守护线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
daemon.setDaemon(true); // 设置为守护线程
daemon.start();
System.out.println("主线程结束");
}
}
特点:
- 不会阻止JVM退出
- 适合执行辅助任务
- finally块可能不会执行
- 谨慎用于资源清理
8.3 线程间简单通信
使用共享对象通信:
java复制public class ThreadCommunication {
static class SharedObject {
private String message;
private boolean empty = true;
public synchronized String take() throws InterruptedException {
while (empty) {
wait();
}
empty = true;
notifyAll();
return message;
}
public synchronized void put(String message) throws InterruptedException {
while (!empty) {
wait();
}
empty = false;
this.message = message;
notifyAll();
}
}
public static void main(String[] args) {
SharedObject channel = new SharedObject();
new Thread(() -> {
try {
channel.put("Hello");
Thread.sleep(1000);
channel.put("World");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
new Thread(() -> {
try {
System.out.println(channel.take());
System.out.println(channel.take());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
9. 综合应用实例
9.1 文件处理工作线程
java复制public class FileProcessor {
private final BlockingQueue<File> fileQueue = new LinkedBlockingQueue<>();
private volatile boolean running = true;
public void startWorkers(int poolSize) {
for (int i = 0; i < poolSize; i++) {
new Thread(() -> {
while (running || !fileQueue.isEmpty()) {
try {
File file = fileQueue.poll(100, TimeUnit.MILLISECONDS);
if (file != null) {
processFile(file);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println(Thread.currentThread().getName() + " 退出");
}, "Worker-" + i).start();
}
}
private void processFile(File file) {
// 模拟文件处理
System.out.println(Thread.currentThread().getName()
+ " 处理文件: " + file.getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public void addFile(File file) {
fileQueue.offer(file);
}
public void shutdown() {
running = false;
}
public static void main(String[] args) throws InterruptedException {
FileProcessor processor = new FileProcessor();
processor.startWorkers(3);
// 添加文件
for (int i = 1; i <= 10; i++) {
processor.addFile(new File("file" + i + ".txt"));
}
Thread.sleep(2000);
processor.shutdown();
}
}
9.2 定时任务执行器
java复制public class ScheduledExecutor {
private final ScheduledExecutorService executor =
Executors.newScheduledThreadPool(2);
public void schedule(Runnable task, long delay, TimeUnit unit) {
executor.schedule(() -> {
try {
task.run();
} catch (Exception e) {
System.err.println("任务执行失败: " + e.getMessage());
}
}, delay, unit);
}
public void scheduleAtFixedRate(Runnable task, long initialDelay,
long period, TimeUnit unit) {
executor.scheduleAtFixedRate(() -> {
try {
task.run();
} catch (Exception e) {
System.err.println("周期任务执行失败: " + e.getMessage());
}
}, initialDelay, period, unit);
}
public void shutdown() throws InterruptedException {
executor.shutdown();
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
public static void main(String[] args) throws InterruptedException {
ScheduledExecutor scheduler = new ScheduledExecutor();
// 一次性任务
scheduler.schedule(() -> System.out.println("延迟任务执行"), 2, TimeUnit.SECONDS);
// 周期性任务
scheduler.scheduleAtFixedRate(
() -> System.out.println("周期任务执行: " + new Date()),
1, 3, TimeUnit.SECONDS);
Thread.sleep(10000);
scheduler.shutdown();
}
}
10. 性能调优与监控
10.1 线程池大小配置
计算公式:
code复制N_threads = N_cpu * U_cpu * (1 + W/C)
其中:
N_cpu = Runtime.getRuntime().availableProcessors()
U_cpu = 目标CPU利用率(0 < U_cpu <= 1)
W/C = 等待时间与计算时间的比率
示例实现:
java复制public class OptimalPoolSize {
public static int calculate(double targetUtilization,
long waitTime, long computeTime) {
int cores = Runtime.getRuntime().availableProcessors();
double ratio = waitTime / (double) computeTime;
return (int) Math.ceil(cores * targetUtilization * (1 + ratio));
}
public static void main(String[] args) {
// 假设任务包含50ms等待和100ms计算
int poolSize = calculate(0.8, 50, 100);
System.out.println("推荐线程池大小: " + poolSize);
}
}
10.2 线程转储分析
获取线程转储的方法:
- 命令行:
jstack <pid> - 程序内:
Thread.getAllStackTraces() - 可视化工具:jvisualvm
分析要点:
- 查找BLOCKED状态的线程
- 检查死锁情况
- 分析线程等待链
- 识别资源竞争点
10.3 监控线程状态
使用JMX监控线程:
java复制public class ThreadMonitoring {
public static void main(String[] args) throws Exception {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
new Timer(true).schedule(new TimerTask() {
@Override
public void run() {
System.out.println("活动线程数: " + threadBean.getThreadCount());
System.out.println("峰值线程数: " + threadBean.getPeakThreadCount());
System.out.println("守护线程数: " + threadBean.getDaemonThreadCount());
System.out.println("-----");
}
}, 0, 3000);
// 创建一些测试线程
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
Thread.sleep(15000);
}
}
11. 线程安全基础
11.1 synchronized关键字
java复制public class SynchronizedCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
SynchronizedCounter counter = new SynchronizedCounter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终计数: " + counter.getCount()); // 总是2000
}
}
同步原理:
- 方法同步锁住对象实例
- 静态方法同步锁住Class对象
- 同步块可以指定锁对象
- 可重入特性
11.2 volatile关键字应用
java复制public class VolatileExample {
private volatile boolean flag = true;
public void stop() {
flag = false;
}
public void runWork() {
new Thread(() -> {
while (flag) {
// 执行工作
}
System.out.println("工作线程停止");
}).start();
}
public static void main(String[] args) throws InterruptedException {
VolatileExample example = new VolatileExample();
example.runWork();
Thread.sleep(100);
example.stop();
}
}
适用场景:
- 状态标志位
- 一次性安全发布
- 独立观察模式
- 开销较低的读-写锁策略
12. 并发工具类简介
12.1 CountDownLatch应用
java复制public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int workerCount = 3;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(workerCount);
for (int i = 0; i < workerCount; i++) {
new Thread(new Worker(startSignal, doneSignal, "Worker-"+i)).start();
}
System.out.println("准备阶段...");
Thread.sleep(1000); // 模拟准备时间
System.out.println("所有工作线程启动");
startSignal.countDown(); // 释放所有工作线程
doneSignal.await(); // 等待所有工作线程完成
System.out.println("所有工作完成");
}
static class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final String name;
public Worker(CountDownLatch startSignal,
CountDownLatch doneSignal, String name) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.name = name;
}
@Override
public void run() {
try {
startSignal.await(); // 等待启动信号
System.out.println(name + " 开始工作");
Thread.sleep(1000 + (int)(Math.random() * 2000)); // 模拟工作
System.out.println(name + " 完成工作");
doneSignal.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
12.2 CyclicBarrier示例
java复制public class CyclicBarrierDemo {
public static void main(String[] args) {
int threadCount = 3;
CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
System.out.println("所有线程到达屏障,执行屏障动作");
});
for (int i = 0; i < threadCount; i++) {
new Thread(new Task(barrier), "Thread-"+i).start();
}
}
static class Task implements Runnable {
private final CyclicBarrier barrier;
public Task(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 开始阶段1");
Thread.sleep(1000 + (int)(Math.random() * 2000));
System.out.println(Thread.currentThread().getName() + " 完成阶段1");
barrier.await();
System.out.println(Thread.currentThread().getName() + " 开始阶段2");
Thread.sleep(1000 + (int)(Math.random() * 2000));
System.out.println(Thread.currentThread().getName() + " 完成阶段2");
barrier.await();
System.out.println(Thread.currentThread().getName() + " 全部完成");
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
}
}
}
13. 线程池基础
13.1 创建线程池
java复制public class ThreadPoolBasics {
public static void main(String[] args) {
// 固定大小线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(3);
// 可缓存线程池
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 单线程池
ExecutorService singleThread = Executors.newSingleThreadExecutor();
// 定时任务线程池
ScheduledExecutorService scheduledPool =
Executors.newScheduledThreadPool(2);
// 自定义线程池
ThreadPoolExecutor customPool = new ThreadPoolExecutor(
4, // 核心线程数
8, // 最大线程数
60, TimeUnit.SECONDS, // 空闲线程存活时间
new LinkedBlockingQueue<>(100), // 工作队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
// 提交任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
fixedPool.execute(() -> {
System.out.println("执行任务 " + taskId + " 线程: " +
Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
fixedPool.shutdown();
}
}
13.2 线程池配置建议
| 配置项 | 建议值 | 说明 |
|---|---|---|
| 核心线程数 | CPU密集型:N+1 IO密集型:2N+1 |
N=CPU核心数 |
| 最大线程数 | 核心线程数的2-3倍 | 根据任务特性调整 |
| 空闲时间 | 30-60秒 | 平衡资源利用与响应 |
| 工作队列 | 有界队列 | 防止资源耗尽 |
| 拒绝策略 | CallerRunsPolicy 或自定义 |
根据业务需求选择 |
14. 并发集合使用
14.1 ConcurrentHashMap示例
java复制public class ConcurrentMapDemo {
public static void main(String[] args) throws InterruptedException {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 并发添加元素
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
final int threadId = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 100; j++) {
String key = "key-" + threadId + "-" + j;
map.put(key, j);
}
});
threads[i].start();
}
for (Thread t : threads) {
t.join();
}
System.out.println("Map大小: " + map.size());
// 原子操作
map.computeIfAbsent("special", k -> 42);
map.merge("special", 1, Integer::sum);
System.out.println("special值: " + map.get("special"));
}
}
14.2 BlockingQueue应用
java复制public class BlockingQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
// 生产者
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
String item = "Item-" + i;
queue.put(item);
System.out.println("生产: " + item);
Thread.sleep(200);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
String item = queue.take();
System.out.println("消费: " + item);
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
15. 线程封闭技术
15.1 栈封闭示例
java复制public class StackConfinement {
public int process(int value) {
// 基本类型局部变量 - 栈封闭
int result = 0;
for (int i = 0; i < value; i++) {
// 每次循环创建新的对象
Object obj = new Object();
result += i;
}
return result;
}
public static void main(String[] args) {
StackConfinement example = new Stack