Java 多线程核心知识点全总结(超详细)

Java 多线程核心知识点全总结(超详细) 一、多线程基础概念1. 核心定义进程操作系统资源分配的最小单位是运行中的程序实例拥有独立的内存空间堆、栈、方法区等。比如你开一个 IDEA、一个浏览器就是一个进程。线程CPU 调度的最小单位是进程内的执行单元共享所属进程的内存空间拥有独立的程序计数器、虚拟机栈、本地方法栈。一个进程至少有一个线程主线程多线程一个进程内同时运行多个线程实现并发执行提升 CPU 利用率和程序响应速度。单核cpu情况下多线程并不是同时执行而是多个线程交替占用CPU注意1进程和线程都是应用程序在执行过程中的概念动态如果应用程序没有执行则不存在进程和线程。2应用程序是静态的概念进程和线程都是动态的概念有创建就有销毁存在也是暂时的不是永久的。2. 多线程优缺点优点提高 CPU 利用率避免单核阻塞导致整体卡顿提升程序响应速度如 GUI 界面、网络服务模块化设计将复杂任务拆分为多个线程执行。缺点线程创建 / 销毁、上下文切换带来系统开销引发线程安全问题竞态条件、死锁调试难度大幅提升。3. 并发与并行并发Concurrent单核 CPU 通过时间片轮转让多个线程交替执行宏观上同时运行。 一个 CPU 核心多个线程轮流执行看起来像同时跑。并行Parallel多核 CPU 下多个线程真正同时执行。多个 CPU 核心真的同时跑。4. 同步与异步同步调用方必须等待方法执行完成才能继续存在阻塞。异步调用方无需等待任务在后台线程执行完成后通过回调通知。二、线程的创建方式4 种1. 继承 Thread 类步骤继承Thread→ 重写run()→ 创建实例 → 调用start()不是 run ()。特点Java 单继承扩展性差不推荐。class MyThread extends Thread { Override public void run() { System.out.println(继承Thread创建线程); } } // 调用 new MyThread().start();2. 实现 Runnable 接口步骤实现Runnable→ 重写run()→ 传入 Thread 构造器 → 调用start()。特点避免单继承局限推荐基础使用无返回值。class MyRunnable implements Runnable { Override public void run() { System.out.println(实现Runnable创建线程); } } // 调用 new Thread(new MyRunnable()).start();3. 实现 Callable 接口 FutureTask步骤实现Callable→ 重写call()有返回值、可抛异常→ 封装为FutureTask→ 传入 Thread → 调用start()→ 通过Future.get()获取结果。特点支持返回值和异常抛出解决 Runnable 无返回值的缺陷。class MyCallable implements CallableString { Override public String call() throws Exception { return Callable线程执行结果; } } // 调用 FutureTaskString task new FutureTask(new MyCallable()); new Thread(task).start(); String result task.get(); // 阻塞获取结果Runnable 是干完活不汇报Callable 是干完活给你返回结果还能抛异常。4. 线程池创建推荐通过ExecutorService线程池创建复用线程避免频繁创建销毁开销。核心实现Executors工具类、ThreadPoolExecutor自定义线程池。三、Thread 类核心方法1. 关键方法start()启动线程JVM 自动调用run()只能调用一次否则抛IllegalThreadStateException。run()线程执行的业务逻辑直接调用仅为普通方法不会开启线程。sleep(long millis)静态方法线程休眠指定毫秒释放 CPU不释放锁。yield()静态方法线程主动让出 CPU回到就绪状态可能立即再次被调度。join()等待该线程执行完毕再继续用于线程间顺序执行。interrupt()中断线程设置中断标志位非强制停止。isInterrupted()判断线程是否被中断不清除标志位。interrupted()静态方法判断并清除中断标志位。stop()/suspend()/resume()废弃方法强制停止线程易导致数据不一致禁止使用。2. 方法注意点sleep()会抛出InterruptedException抛出后清除中断标志位。join()底层基于wait()实现调用线程会进入等待状态。四、线程的生命周期6 种状态Java 线程状态定义在Thread.State枚举中共 6 种NEW新建创建线程对象未调用start()。RUNNABLE可运行调用start()包含就绪Ready和运行中RunningJava 合并为一种状态。BLOCKED阻塞等待获取同步锁进入锁池队列。WAITING无限等待调用wait()、join()、LockSupport.park()无超时时间需其他线程唤醒。TIMED_WAITING计时等待调用sleep(long)、wait(long)、join(long)超时自动唤醒。TERMINATED终止线程执行完毕、异常终止。状态转换流程NEW → start() → RUNNABLE ↔ BLOCKED/WAITING/TIMED_WAITING → TERMINATED五、线程安全与同步机制1. 线程安全问题根源共享资源多个线程同时读写共享变量实例变量、静态变量。竞态条件执行结果依赖线程执行的先后顺序。原子性、可见性、有序性被破坏。2. 解决线程安全同步机制1synchronized 关键字内置锁 / 隐式锁作用保证代码原子性、可见性、有序性同一时间只有一个线程执行同步代码。三种使用方式修饰实例方法锁当前对象实例。修饰静态方法锁当前类的 Class 对象全局锁。修饰代码块锁指定对象粒度更细推荐。// 同步代码块 public void method() { synchronized (this) { // 锁对象 // 同步逻辑 } }底层JVM 层面实现基于monitorenter/monitorexit指令JDK 1.6 后优化偏向锁、轻量级锁、重量级锁。2Lock 接口显式锁JUC 包核心实现ReentrantLock可重入锁、ReentrantReadWriteLock读写锁。优势支持可响应中断、超时获取锁、公平锁 / 非公平锁、多个 Condition。Lock lock new ReentrantLock(); lock.lock(); // 获取锁 try { // 同步逻辑 } finally { lock.unlock(); // 必须在finally释放锁避免死锁 }3volatile 关键字作用保证变量可见性、禁止指令重排不保证原子性。适用场景状态标记量如volatile boolean flag false。原理内存屏障、缓存一致性协议MESI。六、线程间通信1. 基于 Object 的 wait/notify/notifyAll必须在synchronized同步代码内使用否则抛IllegalMonitorStateException。wait()释放锁线程进入等待队列notify()随机唤醒一个等待线程notifyAll()唤醒所有等待线程推荐避免死锁。2. 基于 Condition 的 await/signal/signalAll配合Lock使用一个 Lock 可创建多个 Condition实现精准唤醒。Lock lock new ReentrantLock(); Condition condition lock.newCondition(); lock.lock(); try { condition.await(); // 等待 condition.signal(); // 唤醒 } finally { lock.unlock(); }3. 线程间通信工具CountDownLatch倒计时门栓等待多个线程完成。CyclicBarrier循环屏障线程相互等待达到屏障点。Semaphore信号量控制并发线程数。七、线程池重点1. 线程池优势复用线程减少创建 / 销毁开销控制并发线程数统一管理线程。2. 核心类与接口Executor顶层接口仅定义execute(Runnable)。ExecutorService线程池核心接口扩展Executor提供submit()、shutdown()等方法。ThreadPoolExecutor线程池真正实现类自定义线程池的核心。Executors工具类快速创建线程池生产环境禁止使用。3. ThreadPoolExecutor 7 大参数public ThreadPoolExecutor( int corePoolSize, // 核心线程数常驻线程 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 非核心线程空闲存活时间 TimeUnit unit, // 时间单位 BlockingQueueRunnable workQueue, // 任务队列 ThreadFactory threadFactory, // 线程工厂自定义线程名、优先级 RejectedExecutionHandler handler // 拒绝策略 )4. 线程池执行流程任务提交 → 核心线程数未满 → 创建核心线程执行核心线程满 → 任务加入阻塞队列阻塞队列满 → 非核心线程数未满 → 创建非核心线程执行最大线程数 队列满 → 执行拒绝策略。5. 阻塞队列类型ArrayBlockingQueue有界队列数组实现。LinkedBlockingQueue无界 / 有界队列链表实现Executors.newFixedThreadPool 使用。SynchronousQueue不存储元素提交即创建线程Executors.newCachedThreadPool 使用。PriorityBlockingQueue优先级队列。6. 拒绝策略4 种内置AbortPolicy默认抛RejectedExecutionException。CallerRunsPolicy调用者线程执行任务推荐生产使用。DiscardPolicy直接丢弃任务。DiscardOldestPolicy丢弃队列最老任务执行当前任务。7. Executors 常见线程池禁止生产使用newFixedThreadPool固定线程数无界队列OOM 风险。newSingleThreadExecutor单线程无界队列OOM 风险。newCachedThreadPool缓存线程最大线程数 Integer.MAX_VALUEOOM 风险。newScheduledThreadPool定时任务线程池。8. 线程池关闭shutdown()平缓关闭拒绝新任务执行完已有任务。shutdownNow()立即关闭中断正在执行的任务返回未执行任务列表。八、JUC 并发工具类java.util.concurrent1. CountDownLatch作用一个线程等待多个线程执行完毕再执行不可复用。核心方法countDown()计数减 1、await()等待计数为 0。2. CyclicBarrier作用多个线程相互等待达到屏障点后同时执行可复用。核心方法await()线程到达屏障。3. Semaphore作用控制同时访问资源的线程数用于限流。核心方法acquire()获取许可、release()释放许可。4. Exchanger作用两个线程交换数据仅适用于双线程通信。九、Java 锁机制详解1. 可重入锁定义线程获取锁后再次获取该锁不会阻塞避免死锁。实现synchronized、ReentrantLock均为可重入锁。2. 公平锁 vs 非公平锁公平锁按申请顺序获取锁ReentrantLock(true)。非公平锁线程可插队获取锁效率高默认synchronized也是非公平锁。3. 读写锁ReadWriteLock实现ReentrantReadWriteLock分离读锁和写锁。规则读锁共享多线程同时读写锁独占单线程写写锁优先级高于读锁。适用场景读多写少的场景提升并发性能。4. 乐观锁 vs 悲观锁悲观锁认为一定会有并发冲突操作前加锁synchronized、Lock。乐观锁认为无冲突操作后校验版本号无锁机制CAS 实现。5. CASCompare And Swap定义比较并交换无锁原子操作CPU 原语支持。参数内存值 (V)、预期值 (A)、新值 (B)VA 则替换为 B否则重试。问题ABA 问题解决加版本号 AtomicStampedReference、循环耗时、只能保证单个变量原子性。应用AtomicInteger、AtomicLong等原子类。6. 分段锁定义将数据分段每段加独立锁提升并发度如ConcurrentHashMap1.7 实现。十、JUC 原子类java.util.concurrent.atomic基于 CAS 实现无锁原子操作保证单个变量的原子性基本类型AtomicInteger、AtomicLong、AtomicBoolean。数组类型AtomicIntegerArray、AtomicLongArray。引用类型AtomicReference、AtomicStampedReference解决 ABA。字段更新器AtomicIntegerFieldUpdater更新对象字段。十一、ThreadLocal1. 核心作用线程本地变量每个线程独立拥有副本互不干扰解决线程安全问题。2. 核心方法set(T value)设置当前线程变量。get()获取当前线程变量。remove()移除当前线程变量必须调用避免内存泄漏。3. 内存泄漏问题原因ThreadLocalMap中 Entry 为弱引用Key 被回收后 Value 强引用无法回收。解决使用完ThreadLocal必须调用remove()。十二、死锁1. 死锁定义多个线程相互持有对方需要的锁且不释放自己的锁导致无限阻塞。2. 死锁四大必要条件同时满足互斥条件资源独占同一时间仅一个线程持有。请求与保持线程持有锁又请求其他锁。不可剥夺条件锁只能主动释放不能被强制剥夺。循环等待条件线程形成环形等待链。3. 死锁解决 / 避免破坏任意一个必要条件按固定顺序获取锁破坏循环等待。使用定时锁tryLock(long timeout)破坏不可剥夺。避免一个线程同时持有多个锁。检测jstack命令排查死锁。十三、并发编程三大特性原子性操作不可中断要么全部执行要么不执行synchronized、Lock、CAS。可见性一个线程修改共享变量其他线程立即感知volatile、synchronized、Lock。有序性禁止指令重排代码按预期顺序执行volatile、happens-before 原则。happens-before 原则程序次序规则、锁规则、volatile 规则、传递性规则等保证多线程下的有序性。十四、线程调度与优先级线程优先级1~10默认 5setPriority(int)设置。注意优先级仅为调度建议依赖操作系统不保证严格执行。十五、Java 线程优化与最佳实践禁止使用 Executors 创建线程池自定义ThreadPoolExecutor。锁粒度尽可能小优先使用同步代码块而非同步方法。读多写少场景使用ReentrantReadWriteLock。无状态变量优先使用volatile避免锁开销。使用ThreadLocal后必须remove()防止内存泄漏。避免死锁固定锁顺序、使用定时锁、减少锁嵌套。线程池参数根据业务调整核心线程数 CPU 核心数 /(1 - 阻塞系数)CPU 密集型设为核心数 1IO 密集型设为 2 * 核心数。