Java 并发编程核心知识点

一、并发编程基础概念

1. 进程与线程

核心定义
  • 进程:程序运行的实例,是操作系统资源分配(以内存为主)的最小单位。进程拥有独立的内存空间、IO 资源等,进程间相互独立,通信复杂(IPC 机制或网络协议)。
  • 线程:CPU 调度的最小单位,依赖进程存在,是进程内的执行实体。线程仅拥有程序计数器、寄存器、栈等必要资源,共享所属进程的全部资源,线程间通信简单(共享内存)。
核心区别
对比维度 进程 线程
资源分配 最小单位 无独立资源(共享进程资源)
调度单位 操作系统调度进程 CPU 调度线程
通信复杂度 复杂(IPC / 网络协议) 简单(共享内存)
上下文切换成本

2. 并发与并行

  • 并发(Concurrent):同一时间单位内交替执行多个任务(微观串行,宏观并行)。例如单 CPU 核心下多线程切换执行。
  • 并行(Parallel):同一时刻同时执行多个任务。例如多核 CPU 下,每个核心独立调度线程执行。

3. 上下文切换

  • 定义:CPU 从一个线程 / 进程切换到另一个线程 / 进程时,保存当前线程 / 进程的 CPU 状态(寄存器、程序计数器等),加载目标线程 / 进程状态的过程。
  • 成本:一次上下文切换需 5000~20000 个时钟周期,远高于普通指令执行成本,是并发编程性能损耗的核心原因之一。
  • 触发场景:线程 / 进程切换、系统调用、IO 阻塞等。

二、Java 线程核心知识点

1. Java 线程的创建方式

  • 方式 1:继承 Thread 类,重写 run () 方法(线程与任务耦合)。

    Thread t1 = new Thread("t1") {
    @Override
    public void run() {
    System.out.println("Thread run");
    }
    };
    t1.start();

  • 方式 2:实现 Runnable 接口,配合 Thread 类(线程与任务解耦,推荐)。

    Runnable task = () -> System.out.println("Runnable run");
    Thread t2 = new Thread(task, "t2");
    t2.start();

扩展方式(本质基于 Runnable)
  • 方式 3:实现 Callable 接口,配合 FutureTask(支持任务返回值)。

    FutureTask<Integer> task = new FutureTask<>(() -> {
    System.out.println("Callable run");
    return 100;
    });
    new Thread(task, "t3").start();
    Integer result = task.get(); // 阻塞获取结果

面试易错点
  • 误区:认为 Callable 是独立的创建方式。本质:Callable 需通过 FutureTask 包装为 Runnable,再交给 Thread 执行,属于 Runnable 方式的扩展。

2. Java 线程生命周期(6 种状态)

状态定义(Thread.State 枚举)
  1. NEW:线程对象创建但未调用 start () 方法。
  2. RUNNABLE:包含就绪(ready)和运行中(running)状态,线程等待 CPU 调度或正在执行。
  3. BLOCKED:线程阻塞于锁(synchronized 竞争失败)。
  4. WAITING:线程等待其他线程通知(Object.wait ()、Thread.join () 等),无超时时间。
  5. TIMED_WAITING:带超时时间的等待(Thread.sleep (long)、Object.wait (long) 等)。
  6. TERMINATED:线程执行完毕或异常终止。

3. 线程核心方法

关键方法对比
方法名 静态属性 功能说明 注意事项
start() 启动线程,进入就绪状态,触发 run () 执行 不可重复调用,否则抛 IllegalThreadStateException
run() 线程执行的任务逻辑 直接调用仅为普通方法,不启动新线程
join() 等待线程执行完毕 用于线程同步
sleep(long n) 当前线程休眠 n 毫秒,不释放锁 可被 interrupt () 中断,抛出 InterruptedException
yield() 让出 CPU 使用权,进入就绪状态 仅为提示,调度器可忽略
interrupt() 中断线程 阻塞线程会抛异常并清空中断标记,运行中线程仅设标记
isInterrupted() 判断线程是否被中断 不清除中断标记
interrupted() 判断当前线程是否被中断 清除中断标记
常用方法区别
  • sleep vs yield
    • sleep:主动休眠,释放 CPU,不释放锁,休眠时间可指定。
    • yield:主动让出 CPU,不释放锁,无休眠时间,仅让优先级相同或更高的线程有机会执行。
  • wait vs notify/notifyAll
    • 必须在 synchronized 代码块中调用,调用时释放对象锁。
    • wait:线程进入等待队列,需被 notify/notifyAll 唤醒。
    • notify:唤醒一个等待线程,notifyAll:唤醒所有等待线程。

4. 守护线程

  • 定义:服务于非守护线程的线程,当所有非守护线程结束时,守护线程无论是否执行完毕都会被强制终止。
  • 应用场景:垃圾回收器、心跳检测、事件监听等后台任务。
  • 创建方式thread.setDaemon(true)(需在 start () 前调用)。

三、并发编程核心机制

1. 线程间通信方式

核心方式
通信方式 适用场景 特点
共享内存(volatile / 共享变量) 简单数据传递 需保证可见性、原子性
管道流(PipedInputStream/PipedOutputStream) 线程间字节 / 字符传输 基于内存,无需磁盘 IO
等待 / 通知机制(wait/notify、LockSupport) 线程协作(生产者 - 消费者) 高效,减少轮询开销
Thread.join() 线程顺序执行 同步等待线程完成
等待 / 通知机制规范
  • 等待方:获取锁 → 条件不满足则 wait () → 被唤醒后再次检查条件 → 执行逻辑。

    synchronized (lock) {
    while (!condition) {
    lock.wait(); // 避免虚假唤醒,必须用while循环
    }
    // 业务逻辑
    }

  • 通知方:获取锁 → 修改条件 → 通知所有等待线程。

    synchronized (lock) {
    condition = true;
    lock.notifyAll(); // 优先用notifyAll,避免唤醒错误线程
    }

LockSupport(park/unpark)
  • 无需锁支持,可在任意位置阻塞 / 唤醒线程。

  • 支持先 unpark 后 park(不会阻塞),适合复杂线程协作场景。

    Thread t = new Thread(() -> {
    LockSupport.park(); // 阻塞
    System.out.println("被唤醒");
    });
    t.start();
    LockSupport.unpark(t); // 唤醒

2. 线程同步机制

核心同步方式
  • volatile
    • 保证可见性(一个线程修改后,其他线程立即可见)和有序性(禁止指令重排序)。
    • 不保证原子性,适用于 "单写多读" 场景。
  • synchronized
    • 保证原子性、可见性、有序性,是重量级锁(JDK1.6 后优化为偏向锁、轻量级锁、重量级锁)。
    • 可修饰方法、代码块,锁对象为类对象或实例对象。
  • Lock 接口(ReentrantLock 等)
    • 可重入、可中断、可超时、支持公平锁 / 非公平锁,灵活性高于 synchronized。
    • 需手动释放锁(try-finally 中调用 unlock ())。
原子操作
  • CAS(Compare and Swap):无锁同步机制,通过硬件指令保证原子性。
  • Atomic 类:基于 CAS 实现,如 AtomicInteger、AtomicReference 等,支持原子性的增删改操作。

四、并发设计模式

1. 优雅终止线程:两阶段终止模式

核心思想
  • 第一阶段:发送终止请求(通过 interrupt () 唤醒阻塞线程)。
  • 第二阶段:线程检查终止标志位,执行清理工作后退出。
实现代码
复制代码
public class MonitorThread extends Thread {
    private volatile boolean terminated = false; // 终止标志位

    @Override
    public void run() {
        while (!terminated && !Thread.interrupted()) {
            try {
                System.out.println("监控中...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 重置中断标志
                break;
            }
        }
        System.out.println("执行清理工作...");
    }

    public void terminate() {
        terminated = true;
        this.interrupt(); // 唤醒阻塞线程
    }
}
线程池终止
  • shutdown():拒绝新任务,等待队列中任务执行完毕后关闭。
  • shutdownNow():拒绝新任务,中断正在执行的任务,返回未执行的任务列表。

2. 避免共享:三大设计模式

模式 核心思想 应用场景 注意事项
不变性模式 对象创建后状态不可修改(final 修饰属性 + 只读方法) 缓存、配置信息、值对象 需保证属性对象也不可变
写时复制模式(Copy-on-Write) 写操作时复制副本,修改后替换原数据 读多写少场景(如路由表) 写操作消耗内存,适用于写少场景
线程本地存储模式(ThreadLocal) 为每个线程分配独立存储,数据隔离 保存线程上下文(如用户会话) 线程池环境需手动 remove (),避免内存泄漏
ThreadLocal 内存泄漏问题
  • 原因:ThreadLocalMap 中 Entry 的 key 为弱引用,线程结束后若未手动清理,value 可能被长期引用。
  • 解决方案:使用后调用threadLocal.remove()清理。

3. 多线程分工模式

模式 核心思想 应用场景 实现方式
Thread-Per-Message 为每个任务创建独立线程 低并发异步场景(如定时任务) new Thread ()(高并发需线程池)
Worker Thread 线程池复用线程,避免频繁创建销毁 高并发场景(如服务端处理请求) Executors.newFixedThreadPool () 等
生产者 - 消费者模式 生产者生产任务入队,消费者从队列取任务执行 任务解耦、削峰填谷 BlockingQueue + 线程池
生产者 - 消费者模式实现
复制代码
public class ProducerConsumer {
    private static final BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);

    public static void main(String[] args) {
        // 生产者
        new Thread(() -> {
            try {
                while (true) {
                    queue.put("任务");
                    System.out.println("生产任务,队列大小:" + queue.size());
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 消费者
        new Thread(() -> {
            try {
                while (true) {
                    String task = queue.take();
                    System.out.println("消费任务,队列大小:" + queue.size());
                    Thread.sleep(2000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

4. 多线程版本 if 模式

模式 核心思想 区别 应用场景
守护挂起模式(Guarded Suspension) 条件不满足时线程等待,直到条件满足 等待条件满足后执行 join ()、Future 实现
避免执行模式(Balking) 条件不满足时直接返回,不等待 无需等待,直接放弃 自动保存、单次初始化
相关推荐
宇木灵18 分钟前
C语言基础-十、文件操作
c语言·开发语言·学习
追随者永远是胜利者23 分钟前
(LeetCode-Hot100)207. 课程表
java·算法·leetcode·go
云泽8081 小时前
C++ 多态入门:虚函数、重写、虚析构及 override/final 实战指南(附腾讯面试题)
开发语言·c++
yanghuashuiyue2 小时前
lambda+sealed+record
java·开发语言
盟接之桥2 小时前
盟接之桥EDI软件:API数据采集模块深度解析,打造企业数据协同新引擎
java·运维·服务器·网络·数据库·人工智能·制造
yzx9910132 小时前
Python数据结构入门指南:从基础到实践
开发语言·数据结构·python
HoneyMoose3 小时前
Spring Boot 2.4 部署你的第一个 Spring Boot 应用需要的环境
java
皮皮林5513 小时前
为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解??
java
衍生星球3 小时前
【JSP程序设计】Servlet对象 — page对象
java·开发语言·servlet·jsp·jsp程序设计
vx-Biye_Design3 小时前
servlet家政公司管理系统-计算机毕业设计源码01438
java·vue.js·spring·servlet·tomcat·maven·mybatis