一、并发编程三大核心问题

所有并发难点都来自这 3 点:

  1. 原子性:操作不可中断,要么全部成功,要么全部失败
  2. 可见性:一个线程修改值,另一个线程能立即看到
  3. 有序性:代码按顺序执行,不被指令重排优化

二、核心基础:线程创建方式

4 种写法,掌握前 2 个足够:

  1. 继承 Thread
  2. 实现 Runnable(无返回值)
  3. 实现 Callable(有返回值 + 抛异常)
  4. 线程池(企业标准用法,必用)

三、锁核心:synchronized

1. 作用

保证原子性 + 可见性,解决线程安全问题。

2. 锁的位置

  • 修饰普通方法:锁当前对象 this
  • 修饰静态方法:锁类对象(.class)
  • 修饰代码块:锁括号里的对象

3. 底层原理

  • 依赖 JVM 指令 monitorenter / monitorexit
  • JDK 1.6 后优化:偏向锁 → 轻量级锁 → 重量级锁

四、volatile 关键字(高频)

1. 作用

  1. 保证可见性
  2. 禁止指令重排
  3. 不保证原子性

2. 使用场景

  • 状态标记量(如 volatile boolean flag = false
  • 单例模式 DCL 双重校验锁

五、Lock 锁体系(比 synchronized 更灵活)

1. 核心接口

java.util.concurrent.locks.Lock

2. 常用实现

  • ReentrantLock:可重入锁(常用)
  • ReentrantReadWriteLock:读写锁(读共享,写互斥)

3. 标准用法

Lock lock = new ReentrantLock();
lock.lock(); // 加锁
try {
    // 业务代码
} finally {
    lock.unlock(); // 必须在 finally 释放锁
}

4. 优点

  • 可尝试获取锁
  • 可中断
  • 可设置超时
  • 可指定公平/非公平

六、AQS 原理(锁的底层)

AbstractQueuedSynchronizer
所有 Lock 锁的底层基石。

核心:

  • state 变量:表示锁状态(0=无锁,1=已锁定)
  • CLH 队列:存放等待锁的线程
  • CAS 操作:无锁修改 state,高效

七、线程池(企业开发 100% 用)

1. 为什么要用?

  • 避免频繁创建销毁线程
  • 控制并发数量
  • 统一管理

2. 核心参数(必须背)

new ThreadPoolExecutor(
    corePoolSize,      // 核心线程数
    maximumPoolSize,   // 最大线程数
    keepAliveTime,     // 空闲线程存活时间
    unit,              // 时间单位
    workQueue,         // 阻塞队列
    threadFactory,     // 线程工厂
    handler           // 拒绝策略
);

3. 执行流程

  1. 任务来了 → 核心线程未满 → 创建核心线程
  2. 核心线程满 → 放入阻塞队列
  3. 队列满 → 创建非核心线程
  4. 总线程满 → 执行拒绝策略

4. 常用线程池(面试)

  • Executors.newFixedThreadPool:固定线程
  • Executors.newSingleThreadExecutor:单线程
  • Executors.newCachedThreadPool:缓存线程
    ⚠️ 生产禁用 Executors 创建,必须手动 new ThreadPoolExecutor

八、并发工具类(高频)

1. CountDownLatch

  • 倒计时门栓
  • 让一个线程等待其他 N 个线程完成

2. CyclicBarrier

  • 循环屏障
  • 一组线程互相等待,集齐后一起执行

3. Semaphore

  • 信号量
  • 控制同时执行的线程数量(限流)

九、ThreadLocal

作用

每个线程拥有独立变量副本,互不干扰。

注意

  • 必须 remove(),否则会内存泄漏

十、线程状态(6 种)

  1. NEW(新建)
  2. RUNNABLE(运行)
  3. BLOCKED(阻塞)
  4. WAITING(等待)
  5. TIMED_WAITING(限时等待)
  6. TERMINATED(终止)

十一、死锁(高频)

4 个条件(同时满足)

  1. 互斥
  2. 不可剥夺
  3. 请求保持
  4. 循环等待

解决

  • 固定顺序获取锁
  • 设置锁超时
  • 破坏循环等待

十二、高频面试题(直接背答案)

  1. synchronized 和 Lock 区别?

    • synchronized 是 JVM 层面,Lock 是 JDK 代码
    • synchronized 自动释放锁,Lock 手动
    • Lock 更灵活(可尝试、可超时)
  2. volatile 为什么不能保证原子性?
    因为 volatile 只保证可见性,不保证多步操作的原子性。

  3. 线程池参数有哪些?拒绝策略?
    7 个参数;4 种策略:抛异常、丢弃、丢弃最老、调用者执行

  4. 死锁如何排查?
    jstack 查看线程堆栈

  5. ConcurrentHashMap 1.8 如何保证安全?
    CAS + synchronized + volatile


十三、学习路线(最快掌握)

  1. 线程创建
  2. synchronized
  3. volatile
  4. Lock & AQS
  5. 线程池
  6. 并发工具类
  7. ThreadLocal
  8. 死锁

总结

  • 可见性/有序性:volatile
  • 原子性:synchronized、Lock
  • 高效锁:CAS + AQS
  • 企业必用:线程池
  • 线程安全集合:ConcurrentHashMap、CopyOnWriteArrayList
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐