Java 多线程与并发编程很多人学并发一上来就背八股synchronizedCASAQSvolatileJUC结果背了一堆。问“为什么会线程不安全”直接卡死。其实并发编程最重要的是建立整体认知。这篇从线程锁CASAQSvolatileThreadLocal线程池一路讲到面试常问。尽量人话。一、线程与进程的区别1. 资源分配和调度单位进程是操作系统资源分配的基本单位。线程是 CPU 调度的基本单位。简单理解进程 公司 线程 员工一个进程里可以有多个线程。2. 地址空间不同进程内存隔离。每个进程都有自己的堆栈页表虚拟内存线程共享进程资源。包括堆方法区全局变量但线程有自己的栈程序计数器寄存器3. 通信方式进程通信需要 IPC管道socket消息队列共享内存线程因为共享内存。直接读变量即可。4. 创建和切换开销进程切换时需要切换地址空间。开销大。线程共享地址空间。切换轻很多。5. 稳定性进程之间互相隔离。一个进程崩一般不会影响别的进程。线程共享内存。一个线程乱写整个进程都可能寄。二、为什么进程创建和销毁开销大1. 独立虚拟内存每个进程都需要页表堆栈PCB创建时都要重新初始化。2. 地址空间切换进程切换需要切页表刷TLB切MMU映射线程很多时候不需要。3. 资源回收复杂进程结束需要回收文件socket锁内存三、平台线程与虚拟线程1. 平台线程传统 Java 线程。1:1 对应 OS线程。Java Thread OS Thread特点重栈内存大创建数量有限2. 虚拟线程Java21 正式推出。虚拟线程是 JVM 管理的轻量线程。适合高并发 IO 场景。原理传统线程线程执行IO ↓ 线程阻塞 ↓ OS线程被占住虚拟线程虚拟线程执行IO ↓ JVM挂起虚拟线程 ↓ 平台线程继续执行别的任务所以虚拟线程本质是减少 OS线程浪费。四、Java线程创建方式1. 继承 ThreadclassMyThreadextendsThread{publicvoidrun(){}}2. Runnable推荐。classTaskimplementsRunnable{publicvoidrun(){}}3. Callable FutureTask支持返回值异常4. 线程池实际开发最常用。五、线程状态1. NEW未启动。2. RUNNABLE运行或等待CPU。3. BLOCKED等待锁。4. WAITING无限等待。5. TIMED_WAITING限时等待。6. TERMINATED结束。六、sleep 和 wait 的区别1. sleep 不释放锁2. wait 释放锁3. wait 必须在 synchronized 中调用否则IllegalMonitorStateException4. wait 需要 notify 唤醒七、线程通信方式1. 共享变量2. volatile保证可见性不保证原子性3. wait / notify线程协作。4. BlockingQueue生产者消费者核心。八、为什么会线程不安全本质多个线程同时修改共享资源。比如count实际读取 修改 写回不是原子操作。九、synchronized详解这是 Java 最经典的锁。1. synchronized怎么用修饰普通方法publicsynchronizedvoidtest(){}锁的是当前对象。即this修饰静态方法publicstaticsynchronizedvoidtest(){}锁的是Class对象修饰代码块synchronized(lock){}锁指定对象。2. synchronized底层原理本质对象监视器MonitorJVM通过monitorenter monitorexit实现加锁解锁。3. synchronized支持重入吗支持。synchronized(this){synchronized(this){}}同线程可重复获得锁。4. synchronized 是公平锁吗不是。属于非公平锁。5. synchronized 可以锁字符串吗可以。但不推荐。比如synchronized(abc)字符串常量池可能导致莫名锁竞争。抽象的一批。6. synchronized 锁升级过程JDK6后优化很大。锁会升级无锁 ↓ 偏向锁 ↓ 轻量级锁 ↓ 重量级锁偏向锁默认偏向第一个线程。减少CAS。轻量级锁线程竞争不激烈。采用CAS自旋。重量级锁竞争严重。线程阻塞。OS介入。7. JVM对synchronized做了什么优化锁粗化多个连续加锁合并。锁消除JIT发现没有竞争。直接去掉锁。自旋锁避免线程立即阻塞。偏向锁减少无竞争成本。十、volatile详解1. volatile有什么作用保证可见性有序性不保证原子性2. 什么是可见性线程修改变量后。别的线程立刻能看到。3. 什么是有序性防止指令重排序。4. volatile如何实现底层内存屏障。5. volatile能保证线程安全吗不能。count仍然线程不安全。6. volatile 和 synchronized 区别对比volatilesynchronized原子性不保证保证可见性保证保证有序性保证保证性能高较低十一、CAS详解1. 什么是CASCompare And Swap。比较并交换。CPU原子指令。2. CAS流程V A ? 是 修改成B 否 失败重试3. CAS有什么问题ABA问题值A → B → ACAS会认为没变化。自旋开销大一直失败会疯狂循环。只能保证单变量原子性4. 如何解决ABA问题使用AtomicStampedReference加版本号。十二、AQS详解AQSAbstractQueuedSynchronizerJUC核心。1. AQS是什么一个队列同步器。很多锁都基于它ReentrantLockCountDownLatchSemaphore2. AQS核心思想维护volatileintstate通过CAS修改state。失败线程进入队列等待。3. AQS底层结构CLH双向队列。十三、ReentrantLock1. ReentrantLock 和 synchronized区别ReentrantLock功能更多支持公平锁可中断超时Conditionsynchronized更简单JVM级别优化。2. 公平锁和非公平锁公平锁先来先得。非公平锁允许插队。吞吐量更高。十四、ThreadLocal1. ThreadLocal是什么线程局部变量。每个线程独立副本。2. ThreadLocal原理每个线程内部有ThreadLocalMap3. 为什么key是弱引用避免ThreadLocal无法回收。4. 为什么还会内存泄漏key被回收value可能还在。如果线程池线程不结束value可能一直存在。5. 如何避免使用后remove()十五、线程池详解这是面试高频。1. 为什么使用线程池避免频繁创建销毁线程。2. ThreadPoolExecutor核心参数corePoolSize核心线程数。maximumPoolSize最大线程数。keepAliveTime空闲线程存活时间。workQueue任务队列。threadFactory线程工厂。rejectHandler拒绝策略。3. 线程池执行流程任务来了 ↓ 核心线程没满 → 创建核心线程 ↓ 核心线程满 → 进入队列 ↓ 队列满 → 创建非核心线程 ↓ 线程也满 → 拒绝策略4. 拒绝策略有哪些AbortPolicy默认。直接抛异常。CallerRunsPolicy调用者自己执行。DiscardPolicy直接丢弃。DiscardOldestPolicy丢弃最旧任务。5. 为什么不推荐 Executors因为可能导致OOM。比如newFixedThreadPool队列无界。6. 线程池参数怎么设置CPU密集型CPU核数 1IO密集型CPU核数 * 2或者更高。十六、死锁1. 什么是死锁多个线程互相等待资源。谁也不释放。2. 死锁四个条件互斥请求保持不可剥夺循环等待3. 如何避免死锁固定加锁顺序超时机制减少锁嵌套十七、并发容器1. ConcurrentHashMapJDK8CASsynchronized实现。2. CopyOnWriteArrayList读写分离。适合读多写少。3. BlockingQueue阻塞队列。线程池核心。十八、悲观锁和乐观锁1. 悲观锁认为一定会冲突。直接加锁。比如synchronized ReentrantLock2. 乐观锁认为不一定冲突。CAS重试。十九、总结并发编程核心其实就三件事1. 资源共享多个线程如何共享数据。2. 线程调度CPU怎么切换线程。3. 数据安全如何避免数据错乱死锁可见性问题很多高级并发框架。底层逃不过CASAQSvolatilesynchronized理解这些。后面看源码才不会像看天书。