一、引言:为什么要学习多线程?随着 CPU 核心数的提升,单线程程序已无法充分发挥硬件性能。Java 提供了强大的并发编程支持,允许我们使用多线程来:
提高程序执行效率
响应多个用户请求(如 Web 服务)
实现异步任务、并发数据处理
构建高性能服务器和框架
二、线程基础2.1 什么是线程?线程(Thread)是进程中的最小执行单元,一个进程可以包含多个线程,多个线程共享进程的资源。
📌 线程 VS 进程:
对比项
进程
线程
定义
资源分配单位
CPU 执行单位
资源
独立资源空间
共享资源(如堆)
通信
开销大
更高效
开销
创建销毁开销大
开销较小
2.2 创建线程的方式方式一:继承 Thread 类代码语言:javascript复制java复制编辑public class MyThread extends Thread {
public void run() {
System.out.println("线程运行:" + Thread.currentThread().getName());
}
}
new MyThread().start();方式二:实现 Runnable 接口代码语言:javascript复制java复制编辑public class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable 线程执行");
}
}
new Thread(new MyRunnable()).start();方式三:使用 Callable + Future代码语言:javascript复制java复制编辑Callable
return "任务完成";
};
FutureTask
new Thread(future).start();
System.out.println(future.get());三、线程的生命周期与状态图📌 线程状态图如下:
代码语言:javascript复制sql复制编辑新建 NEW
↓
就绪 RUNNABLE ← 唤醒
↓
运行 RUNNING
↓ ↑
阻塞 BLOCKED/WAITING/TIMED_WAITING
↓
终止 TERMINATED四、线程同步与锁机制4.1 为什么需要同步?多个线程同时访问共享资源时,可能产生“竞态条件”:
代码语言:javascript复制java复制编辑class Counter {
int count = 0;
public void add() {
count++;
}
}多个线程同时调用 add(),可能导致最终 count 错误。
4.2 synchronized 同步关键字修饰实例方法代码语言:javascript复制java复制编辑public synchronized void add() {
count++;
}修饰代码块代码语言:javascript复制java复制编辑public void add() {
synchronized (this) {
count++;
}
}修饰静态方法(类锁)代码语言:javascript复制java复制编辑public static synchronized void staticMethod() {}📌 原理:
synchronized 会加锁对象的 monitor(监视器锁),底层依赖 JVM 实现。
4.3 死锁示例与避免代码语言:javascript复制java复制编辑public void deadlock() {
synchronized (resourceA) {
synchronized (resourceB) {
// 死锁风险
}
}
}✅ 避免方式:
保持加锁顺序一致
设置超时(如 tryLock())
五、常见并发工具类(Java.util.concurrent)5.1 ReentrantLock(可重入锁)代码语言:javascript复制java复制编辑Lock lock = new ReentrantLock();
try {
lock.lock();
// 临界区
} finally {
lock.unlock();
}📌 支持:
公平锁 / 非公平锁
可中断锁
可重入
条件变量(Condition)
5.2 CountDownLatch:等待多个线程完成代码语言:javascript复制java复制编辑CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
// 执行任务
latch.countDown(); // 完成一次
}).start();
}
latch.await(); // 等待3个线程执行完5.3 CyclicBarrier:线程集合后统一执行代码语言:javascript复制java复制编辑CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("三线程到达,开始执行任务");
});适合多个线程协作的场景,例如并行计算。
5.4 Semaphore:控制并发数代码语言:javascript复制java复制编辑Semaphore semaphore = new Semaphore(3);
semaphore.acquire();
try {
// 执行任务
} finally {
semaphore.release();
}控制访问资源的最大线程数,如连接池。
六、线程池详解(Executor 框架)6.1 使用线程池的优势 减少资源创建/销毁开销
提高响应速度
控制最大并发数
6.2 Executors 创建线程池代码语言:javascript复制java复制编辑ExecutorService pool = Executors.newFixedThreadPool(5);
pool.execute(() -> {
System.out.println("线程池任务执行");
});📌 常见线程池类型:
类型
特点
newFixedThreadPool
固定线程数,适合稳定负载
newCachedThreadPool
自动扩容/回收线程,适合短任务
newSingleThreadPool
单线程,适合顺序执行
newScheduledPool
定时任务调度
6.3 自定义线程池参数(推荐)代码语言:javascript复制java复制编辑ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 10,
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);📌 参数说明图解:
代码语言:javascript复制nginx复制编辑corePoolSize → 核心线程数
maximumPoolSize → 最大线程数
keepAliveTime → 空闲线程存活时间
workQueue → 任务队列
handler → 拒绝策略七、线程安全集合类7.1 常见类型类名
描述
ConcurrentHashMap
线程安全的 HashMap
CopyOnWriteArrayList
读多写少的线程安全列表
BlockingQueue
支持阻塞的队列接口
八、volatile 与原子操作类8.1 volatile:可见性关键字代码语言:javascript复制java复制编辑volatile boolean running = true;📌 保证线程间变量的 可见性,但不保证原子性。
8.2 原子类:AtomicInteger代码语言:javascript复制java复制编辑AtomicInteger counter = new AtomicInteger();
counter.incrementAndGet(); // 原子自增基于 CAS(Compare and Swap)机制实现无锁并发。
九、并发问题与调试技巧9.1 经典并发问题问题
说明
竞态条件
多线程抢占资源导致结果异常
死锁
线程互相等待资源,永不释放
饥饿
某线程长期得不到资源
活锁
不停改变状态但无法前进
9.2 常用调试工具与命令 jstack: 查看线程堆栈
VisualVM: 图形化分析工具
Java Flight Recorder: Java 性能监控
十、案例实战:模拟银行取款系统代码语言:javascript复制java复制编辑class Bank {
private int balance = 1000;
public synchronized void withdraw(int amount) {
if (balance >= amount) {
try { Thread.sleep(100); } catch (Exception e) {}
balance -= amount;
System.out.println(Thread.currentThread().getName() + " 取款成功,剩余:" + balance);
} else {
System.out.println(Thread.currentThread().getName() + " 余额不足");
}
}
}代码语言:javascript复制java复制编辑public class Test {
public static void main(String[] args) {
Bank bank = new Bank();
Runnable r = () -> bank.withdraw(800);
new Thread(r, "用户A").start();
new Thread(r, "用户B").start();
}
}📌 观察输出结果并测试同步效果。
十一、总结与进阶方向11.1 本文回顾要点: 多线程基础与创建方式
同步机制(synchronized、Lock)
并发工具类(CountDownLatch、Semaphore 等)
线程池与并发集合
volatile 与原子类
并发调试方法
11.2 推荐进阶方向: 学习 AQS(AbstractQueuedSynchronizer)原理
掌握 Fork/Join 框架
熟练使用 CompletableFuture 异步处理
深入理解 Java 内存模型(JMM)