1. 线程是什么?为什么需要多个线程?

👨‍🍳 类比——厨房:
程序 = 一家餐厅;进程 = 一个厨房;线程 = 厨房里的厨师
一个厨师(单线程):只能一道菜一道菜做——菜 A 在等水烧开时,厨师干等着,浪费!
多个厨师(多线程):菜 A 等水烧开时,厨师 B 可以切菜——同时做多件事,效率高。

线程:程序里同时执行的多条"任务线"。Java 里 new Thread(...).start() 就能开一条新线程。

为什么要用多线程:

感受线程:同时打印
new Thread(() -> {
    for (int i = 1; i <= 5; i++)
        System.out.println("线程1: " + i);
}).start();

for (int i = 1; i <= 5; i++)
    System.out.println("主线程: " + i);

// 输出顺序不固定!两个线程交替执行(由 CPU 调度)
// 可能:主线程:1 线程1:1 主线程:2 线程1:2 ... 交替出现

🎯 记住

  • 线程 = 并行的"任务线";多线程 = 多个厨师同时干活
  • 多线程的代价:抢共享资源会出问题(下一节)
  • 线程不是越多越好(创建/切换有成本)——线程池页详解

2. 为什么多线程会出问题?(并发三大问题)

💰 类比——抢红包计数器:两个线程同时执行 count++:
"读 count → 加 1 → 写回"是三步。两个厨师同时做这三步就会"撞车":
厨师 A 读到 100,厨师 B 也读到 100,都加 1 写回 → 结果 101,丢了一次计数。

并发三大问题(面试必背):

亲手复现:多线程计数错误
static int count = 0;

// 开 2 个线程,各加 10000 次
for (int t = 0; t < 2; t++) {
    new Thread(() -> {
        for (int i = 0; i < 10000; i++) count++;
    }).start();
}
// 最终 count 往往不是 20000,而是 199xx——因为撞车丢了更新
// 这就是"线程不安全":多线程下结果不可预测

🎯 记住

  • 并发问题 = 多个线程"同时"操作共享数据 → 结果不可预测
  • 三大问题:原子性(被插队)、可见性(看不到)、有序性(被重排)
  • 解决思路就是后面整个模块:锁(synchronized)、volatile、原子类

3. 锁(synchronized)是什么?

🚻 类比——公共厕所:多线程抢共享资源就像抢厕所:
synchronized(锁) = 门上锁:一个人进去(拿到锁),其他人只能在门外等(阻塞),里面的人出来(释放锁),下一个才能进。
锁保证:同一时刻只有一个线程执行被锁的代码 → 不会撞车。
用锁修复计数问题
static int count = 0;
static final Object LOCK = new Object();

new Thread(() -> {
    for (int i = 0; i < 10000; i++) {
        synchronized (LOCK) {    // 拿锁 → 执行 → 释放
            count++;
        }
    }
}).start();
// 现在结果稳定是 10000(每个线程自己的 10000 次不互相干扰)
// 代价:加锁会慢一点(排队),所以锁的"范围"越小越好

🎯 记住

  • synchronized = 给代码块"上锁",同一时刻只放一个线程进来
  • 锁要锁"共享数据的操作";锁多了慢,锁少了错——平衡是艺术
  • Java 的锁体系:synchronized(内置锁)→ Lock(ReentrantLock,更灵活)——JUC 页详解

4. 并发学习路径

  1. 本篇:理解线程、并发问题、锁的直觉 ✅
  2. 线程基础:生命周期、创建方式、wait/notify
  3. synchronized & volatile:锁升级原理、可见性
  4. AQS 与 JUC:ReentrantLock、CountDownLatch、原子类、并发容器
  5. 线程池:生产必用,参数与坑

🎯 常见误区

  • 误区 1:"多线程一定快"——线程创建/切换有开销,简单任务单线程更快
  • 误区 2:"加了 volatile 就安全了"——volatile 只管可见性,不管原子性(count++ 照样错)
  • 误区 3:"synchronized 很慢"——现代 JVM 有锁升级优化(偏向锁→轻量级→重量级),大多数场景够快。注意 JDK 15 起偏向锁已默认关闭(JEP 374)

🎤 常见面试追问

  1. 多线程一定比单线程快吗?——不一定:线程创建/切换有开销,任务本身计算量小或已串行依赖时,多线程反而更慢。并发适合"任务可并行"的场景。
  2. 进程和线程的区别?——进程是资源分配单位(独立内存空间);线程是 CPU 调度单位(共享进程内存)。线程切换成本低,但有共享数据竞争问题。
  3. 你项目里哪里用到了多线程?——典型回答:线程池处理异步任务(短信/日志)、并行查询、定时任务。面试官想听"用过 + 知道为什么"。

📖 名词解释(本页术语)

术语 大白话解释
并发(Concurrency)多个任务"同时推进"(单核上交替执行也算并发)。和"并行"(多核真同时执行)不同,面试常考区分。
共享资源多个线程都能访问的同一份数据(全局变量、集合、数据库连接)。并发问题的根源。
锁互斥访问共享资源的机制:拿到锁才能执行临界区,保证同一时刻只有一个线程在改数据。
临界区需要互斥保护的代码段(操作共享数据的部分)。锁的范围 = 临界区的大小。
线程安全 / 线程不安全安全 = 多线程下结果稳定正确;不安全 = 结果不可预测(如 count++ 丢更新)。
⚠️ 本页面由 AI 生成,内容仅供参考,请以官方文档和实际源码为准。