进程 vs 线程
类型 | 定义 | 示例 |
---|---|---|
进程 | 操作系统资源分配的基本单位 | 如一个 QQ 程序就是一个进程 |
线程 | CPU 调度执行的基本单位 | 如 QQ 中的文字聊天、视频聊天是不同线程 |
️ 形象比喻:
进程 = 餐厅
线程 = 服务员
餐厅可以有多个服务员同时工作,但共享餐厅资源(如厨房、餐具)。
创建线程的三种方式
方式1:继承 Thread 类
class MyThread extends Thread {
public void run() {
System.out.println("我爱Java");
}
}
方式2:实现 Runnable 接口
class MyRunnable implements Runnable {
public void run() {
System.out.println("Java也爱我");
}
}
方式3:使用 Callable 和 Future
class MyCallable implements Callable {
public String call() {
return "双向奔赴的爱情";
}
}
✅ 推荐方式:
使用 Runnable / Callable 可避免单继承限制
Callable 支持返回值和抛异常
线程在其生命周期中会经历以下 6种状态:
状态 | 描述 |
---|---|
NEW | 线程刚创建,尚未启动 |
RUNNABLE | 线程正在运行或等待 CPU 时间片 |
BLOCKED | 等待进入 synchronized 代码块/方法 |
WAITING | 无限期等待其他线程唤醒 |
TIMED_WAITING | 在指定时间内自动唤醒(如 sleep、wait(timeout)) |
TERMINATED | 线程执行完毕或异常终止 |
形象比喻:
线程就像在玩滑梯:
NEW → 在排队准备上滑梯
RUNNABLE → 正在滑下来
BLOCKED → 滑梯口被别人占着了
WAITING → 在休息区等下次再玩
TIMED_WAITING → 看了眼手表,知道过会儿就能继续玩
TERMINATED → 家长喊回家吃饭了
1. synchronized 关键字
方法锁
public synchronized void method() {
// 同步代码
}
代码块锁
synchronized(obj) {
// 同步代码
}
2. Lock 接口(更灵活)
Lock lock = new ReentrantLock();
lock.lock();
try {
// 执行代码
} finally {
lock.unlock();
}
3. 线程间通信机制
synchronized(obj) {
while (条件不满足) {
obj.wait(); // 等待
}
// 执行操作
obj.notifyAll(); // 唤醒其他线程
}
形象比喻:
线程通信就像情侣微信聊天:
wait() = “你先说...”
notify() = “收到!轮到我说了”
notifyAll() = 喊了一嗓子“开全体会议啦!”
1. 四种常见线程池类型
ExecutorService pool = Executors.newFixedThreadPool(3); // 固定大小
ExecutorService pool = Executors.newCachedThreadPool(); // 缓存型(按需创建)
ExecutorService pool = Executors.newSingleThreadExecutor(); // 单线程
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); // 调度型(支持定时任务)
2. 自定义线程池(推荐)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(100), // 工作队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
形象比喻:
线程池就像外卖骑手团队:
核心骑手:常驻员工
临时骑手:高峰期加派人手
等待任务队列:排队处理的订单
拒绝策略:超负荷时怎么处理新订单
1. CountDownLatch(倒计时门闩)
适用于主线程等待多个子线程完成后再继续执行。
CountDownLatch latch = new CountDownLatch(3);
// 子线程调用
latch.countDown();
// 主线程等待
latch.await();
形象比喻:
就像火箭发射倒计时:"3...2...1...起飞!"
2. CyclicBarrier(循环屏障)
适用于多个线程相互等待,直到都到达某个屏障点后一起继续执行。
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("大家都到了,开始聚餐!");
});
barrier.await();
形象比喻:
就像朋友约饭:"小明到饭店了..."、"小红到饭店了..."、"小刚终于到了!上菜!"
3. Semaphore(信号量)
用于控制同时访问的线程数量,常用于资源池管理、限流等场景。
Semaphore semaphore = new Semaphore(2); // 允许2个线程同时访问
semaphore.acquire(); // 获取许可
try {
// 执行代码
} finally {
semaphore.release(); // 释放许可
}
形象比喻:
就像停车场管理:"入口处取卡进场"、"出场还卡"
模块 | 核心内容 |
---|---|
基础概念 | 进程与线程区别、创建线程的三种方式 |
线程状态 | 6种状态及转换流程 |
同步与通信 | synchronized、ReentrantLock、wait/notify |
线程池 | 内置线程池与自定义线程池配置 |
并发工具 | CountDownLatch、CyclicBarrier、Semaphore |
学习建议:
多写示例代码,动手实践是掌握并发的关键
结合日志调试观察线程切换和状态变化
实际项目中优先使用线程池 + FutureTask 或 CompletableFuture