1. Java线程基础概念解析
线程作为Java并发编程的核心概念,本质上是一个轻量级的执行单元。与进程相比,线程共享相同的内存空间,这使得线程间的通信更为高效。在JVM中,每个线程都拥有独立的程序计数器、虚拟机栈和本地方法栈,但堆内存和方法区是共享的。
关键区别:进程是资源分配的基本单位,线程是CPU调度的基本单位。一个Java程序启动时至少会创建一个主线程(main线程)
现代操作系统普遍采用时间片轮转的调度算法,Java线程最终会映射到操作系统的原生线程上执行。线程的创建和销毁需要消耗系统资源,这也是为什么在高并发场景下我们更推荐使用线程池。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 线程实现方式详解
2.1 继承Thread类
最基础的实现方式是通过继承java.lang.Thread类:
java复制class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行: " + Thread.currentThread().getName());
}
}
// 启动线程
MyThread thread = new MyThread();
thread.start(); // 注意是start()不是run()
常见误区:直接调用run()方法并不会启动新线程,而是在当前线程中同步执行
这种方式的优点是简单直接,但缺点也很明显:
- Java单继承特性导致无法再继承其他类
- 任务逻辑与线程控制耦合在一起
- 不适合资源共享场景
2.2 实现Runnable接口
更推荐的实现方式是使用Runnable接口:
java复制class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable线程: " + Thread.currentThread().getName());
}
}
// 使用方式
Thread thread = new Thread(new MyRunnable());
thread.start();
优势分析:
- 避免单继承限制
- 任务与线程控制解耦
- 更方便实现资源共享
- 适合线程池等高级用法
2.3 实现Callable接口(带返回值)
需要返回结果的场景可以使用Callable:
java复制class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "任务完成";
}
}
// 使用示例
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get()); // 阻塞获取结果
executor.shutdown();
Callable特点:
- 可以返回执行结果
- 可以抛出检查异常
- 通常配合ExecutorService使用
3. 线程生命周期与状态转换
Java线程的生命周期包含6种状态:
- NEW:新建但未启动
- RUNNABLE:可运行状态(包含就绪和运行中)
- BLOCKED:等待监视器锁
- WAITING:无限期等待
- TIMED_WAITING:限期等待
- TERMINATED:终止状态
状态转换典型场景:
java复制// NEW -> RUNNABLE
Thread t = new Thread(() -> {});
// RUNNABLE -> TIMED_WAITING
Thread.sleep(1000);
// RUNNABLE -> BLOCKED
synchronized(lockObj) {...}
// RUNNABLE -> WAITING
obj.wait();
// 各种状态 -> TERMINATED
t.run()执行结束
诊断技巧:jstack命令可以查看线程当前状态,是排查死锁、线程阻塞的利器
4. 线程安全与同步机制
4.1 同步代码块
最基本的同步方式:
java复制private final Object lock = new Object();
public void safeMethod() {
synchronized(lock) {
// 临界区代码
}
}
4.2 同步方法
方法级同步:
java复制public synchronized void safeMethod() {
// 实例方法锁的是this对象
// 静态方法锁的是Class对象
}
4.3 显式锁(ReentrantLock)
更灵活的锁机制:
java复制private final ReentrantLock lock = new ReentrantLock();
public void safeMethod() {
lock.lock();
try {
// 临界区
} finally {
lock.unlock(); // 必须手动释放
}
}
显式锁优势:
- 可尝试获取锁(tryLock)
- 可中断的获取锁(lockInterruptibly)
- 公平锁选项
- 支持多个条件变量
4.4 原子类(Atomic)
无锁线程安全方案:
java复制private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet(); // CAS操作
}
5. 线程池最佳实践
5.1 核心参数解析
ThreadPoolExecutor的7个核心参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程存活时间
- unit:时间单位
- workQueue:任务队列
- threadFactory:线程工厂
- handler:拒绝策略
5.2 四种预定义线程池
- newFixedThreadPool:固定大小线程池
- newCachedThreadPool:可缓存线程池
- newSingleThreadExecutor:单线程池
- newScheduledThreadPool:定时任务线程池
5.3 自定义线程池示例
生产环境推荐配置:
java复制int coreSize = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
coreSize,
coreSize * 2,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000),
new NamedThreadFactory("biz-pool"),
new ThreadPoolExecutor.CallerRunsPolicy()
);
经验法则:IO密集型任务可以设置较大线程数(2N+1),CPU密集型任务建议N+1
6. 常见问题排查指南
6.1 线程死锁检测
典型死锁特征:
- 多个线程互相持有对方需要的锁
- 所有相关线程都处于BLOCKED状态
- 程序无响应但进程仍在运行
诊断方法:
bash复制jstack <pid> | grep -A 10 deadlock
6.2 内存泄漏排查
线程相关内存泄漏场景:
- 线程池未关闭导致线程无法回收
- 静态集合持有线程引用
- ThreadLocal使用后未清理
检查工具:
- jmap -histo查看对象实例
- MAT分析堆转储文件
6.3 性能优化建议
- 避免过度同步(缩小同步范围)
- 使用读写锁替代独占锁
- 考虑无锁数据结构
- 合理设置线程池参数
- 使用异步编程模型(CompletableFuture)
7. Java线程高级特性
7.1 ThreadLocal原理
线程局部变量实现:
java复制ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> "init");
// 每个线程独立副本
threadLocal.set("thread-value");
String value = threadLocal.get();
注意事项:必须及时remove(),否则可能导致内存泄漏(尤其在线程池环境)
7.2 守护线程
特点:
- 不会阻止JVM退出
- 为其他线程提供服务
- 适合执行后台任务
设置方式:
java复制Thread daemonThread = new Thread(() -> {...});
daemonThread.setDaemon(true);
daemonThread.start();
7.3 Fork/Join框架
分治任务处理:
java复制class FibonacciTask extends RecursiveTask<Integer> {
protected Integer compute() {
// 任务拆分逻辑
}
}
ForkJoinPool pool = new ForkJoinPool();
Integer result = pool.invoke(new FibonacciTask(10));
适用场景:
- 可分解的CPU密集型任务
- 递归算法实现
- 大数据处理
8. 现代并发工具类
8.1 CountDownLatch
倒计时门闩:
java复制CountDownLatch latch = new CountDownLatch(3);
// 工作线程
latch.countDown();
// 主线程
latch.await();
典型应用:
- 多线程任务完成后汇总结果
- 服务启动依赖检查
8.2 CyclicBarrier
循环栅栏:
java复制CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程到达屏障");
});
// 工作线程
barrier.await();
特点:
- 可重复使用
- 支持屏障动作
- 处理阶段性任务
8.3 CompletableFuture
异步编程:
java复制CompletableFuture.supplyAsync(() -> "Hello")
.thenApplyAsync(s -> s + " World")
.thenAccept(System.out::println);
优势:
- 链式调用
- 异常处理
- 组合多个Future
在实际项目中,我发现合理使用CompletableFuture可以显著简化异步编程模型,特别是在微服务调用链场景下。一个实用的技巧是使用thenCombine来处理多个并行任务的聚合结果,这比传统的回调方式要清晰得多。
