Java 并发编程完整讲解 一、并发基础概念1. 并发 vs 并行并发多个任务交替执行单核 CPU 切换线程宏观同时跑微观串行并行多核 CPU 同时执行多个线程真正同一时刻运行2. 进程 线程进程操作系统资源分配最小单位独立内存、文件句柄进程间隔离线程进程内执行单元共享进程堆内存栈独立切换开销远小于进程JVM一个 Java 程序启动就是一个进程默认主线程main3. 三大并发核心问题可见性一个线程修改共享变量其他线程看不到原子性多步操作不可拆分中途不能被其他线程打断i 非原子有序性CPU / 编译器指令重排代码执行顺序和书写不一致4. JMM Java 内存模型JMM 规定线程、主内存、工作内存交互规则所有共享变量存在主内存每个线程私有工作内存缓存寄存器线程读写变量必须拷贝到工作内存不能直接操作主存 三大关键字对应三大特性volatile保证可见性 禁止指令重排不保证原子性synchronized保证原子性 可见性 有序性Lock锁和 synchronized 语义一致API 层面锁二、Java 创建线程的 4 种方式1. 继承 Thread 类javaclass MyThread extends Thread { Override public void run() { System.out.println(线程执行); } } // 使用 new MyThread().start();缺点单继承限制无法再继承其他类2. 实现 Runnable 接口无返回值无异常抛出解耦线程与任务javaRunnable task () - System.out.println(任务); new Thread(task).start();3. Callable FutureTask可抛出异常获取线程执行结果javaCallableInteger call () - 100; FutureTaskInteger ft new FutureTask(call); new Thread(ft).start(); Integer res ft.get(); // 阻塞获取结果4. 线程池 ExecutorService手动创建线程开销大、不可控统一线程池管理javaExecutorService pool Executors.newFixedThreadPool(5); pool.submit(() - {}); pool.shutdown();线程核心方法start()创建内核线程调用 run ()只能调用一次run()普通方法直接调用不会新开线程sleep(long)休眠释放 CPU不释放锁wait()Object 方法释放锁进入等待队列需 notify 唤醒notify()/notifyAll()唤醒等待线程join()主线程等待子线程执行完毕interrupt()中断线程设置中断标记不直接停止三、锁机制1. synchronized 内置锁悲观锁使用场景修饰实例方法锁当前对象this修饰静态方法锁类 Class 对象修饰代码块自定义锁对象java// 实例锁 public synchronized void test(){} // 代码块锁 synchronized (obj) {} // 静态锁 public static synchronized void test(){}底层原理字节码monitorenter/monitorexit对象头 Mark Word 存储锁标记无锁→偏向锁→轻量级锁→重量级锁锁膨胀自动释放锁异常也会释放无需手动解锁优缺点优点语法简单、自动释放、JVM 优化 缺点阻塞不可中断、非公平锁、无法灵活控制2. Lock 显式锁java.util.concurrent.locksReentrantLock 可重入锁javaLock lock new ReentrantLock(); lock.lock(); try { // 临界区 } finally { lock.unlock(); // 必须finally释放防止死锁 }相比 synchronized 优势可中断等待lockInterruptibly()尝试非阻塞获取锁tryLock()公平锁 / 非公平锁可选new ReentrantLock(true)公平多条件等待多个 Condition 区分等待队列ReadWriteLock 读写锁ReentrantReadWriteLock读共享、写互斥读多写少场景缓存提升并发写锁阻塞所有读写StampedLock 乐观读写锁提供乐观读模式无锁开销适合高并发读场景3. 锁分类可重入锁同一线程多次获取同一锁不会死锁synchronized、ReentrantLock 都是公平锁线程按等待顺序获取锁非公平锁抢占吞吐量更高悲观锁默认一定会竞争加锁阻塞synchronized、Lock乐观锁无锁版本号 CAS 判断冲突Atomic、数据库 MVCC自旋锁线程循环尝试获取锁不挂起短等待场景高效四、volatile 关键字作用可见性修改后强制刷新主存其他线程缓存失效立即读取主存禁止指令重排插入内存屏障保证执行顺序局限性不保证原子性volatile int i; i线程不安全典型使用场景状态标记开关变量javavolatile boolean stop false; while(!stop){}双重检查锁 DCL 单例防止指令重排导致半初始化对象javapublic class Singleton { private volatile static Singleton instance; public static Singleton getInstance() { if(instance null) { synchronized (Singleton.class) { if(instance null) instance new Singleton(); } } return instance; } }五、CAS 原子类无锁并发CAS 比较并交换乐观锁核心算法V(内存值) E(预期值) ? 更新为N : 失败重试CPU 硬件指令保证原子操作无锁、无内核切换性能高 问题ABA 问题值 A→B→ACAS 无法感知变化 → 用AtomicStampedReference版本号解决循环自旋消耗 CPU只能单个变量原子操作JUC 原子工具包 java.util.concurrent.atomic基本类型AtomicInteger、AtomicLong、AtomicBooleanjav运行AtomicInteger num new AtomicInteger(0); num.incrementAndGet(); // i原子操作引用类型AtomicReference、AtomicStampedReference解决 ABA数组原子类AtomicIntegerArray对象字段更新器AtomicIntegerFieldUpdater节省对象内存累加器LongAdder高并发下优于 AtomicLong分段计数降低 CAS 竞争六、线程间通信1. wait / notify / notifyAllObject前提必须在 synchronized 同步块内wait ()释放锁阻塞等待等待其他线程 notifynotify ()随机唤醒一个等待线程notifyAll ()唤醒全部等待线程 标准生产者消费者模型基础2. ConditionLock 配套替代 wait/notify支持多等待队列精准唤醒指定线程javaCondition full lock.newCondition(); Condition empty lock.newCondition(); empty.await(); // 等价wait full.signal(); // 等价notify3. CountDownLatch 减法计数器等待 N 个线程完成后主线程再执行javaCountDownLatch latch new CountDownLatch(5); latch.countDown(); // 计数-1 latch.await(); // 阻塞直到计数04. CyclicBarrier 循环屏障多个线程互相等待全部到达屏障点再一起执行可重复使用javaCyclicBarrier barrier new CyclicBarrier(3); barrier.await(); // 3个线程都到这里才放行5. Semaphore 信号量控制并发线程数量限流工具javaSemaphore sem new Semaphore(5); // 最多5个并发 sem.acquire(); // 获取许可 sem.release(); // 释放许可七、线程池1. 为什么要用线程池避免频繁创建销毁线程降低开销控制并发数量防止 CPU 耗尽统一管理线程提供定时、延迟、任务拒绝策略2. ThreadPoolExecutor 七大参数javapublic ThreadPoolExecutor( int corePoolSize, // 核心线程数常驻 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 非核心线程空闲存活时间 TimeUnit unit, // 时间单位 BlockingQueueRunnable workQueue, // 阻塞队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略 )执行流程任务进来核心线程未满 → 创建核心线程执行核心线程满任务放入阻塞队列队列满创建非核心线程直到达到最大线程数总线程达上限执行拒绝策略3. 4 种拒绝策略AbortPolicy默认直接抛 RejectedExecutionExceptionDiscardPolicy丢弃当前任务无异常DiscardOldestPolicy丢弃队列最老任务重试提交CallerRunsPolicy交给提交任务主线程执行限流4. 内置工具类线程池newFixedThreadPool(n)固定线程无界队列任务堆积 OOMnewSingleThreadExecutor()单线程无界队列newCachedThreadPool()可缓存无核心线程最大线程无限线程暴涨 OOMnewScheduledThreadPool()定时 / 延迟任务线程池 生产规范手动 new ThreadPoolExecutor自定义队列、线程数、拒绝策略5. ScheduledExecutorService 定时任务替代 Timer单线程任务失败全部阻塞多线程定时执行八、并发容器 JUC 集合1. 阻塞队列 BlockingQueue生产者消费者核心队列满 / 空自动阻塞ArrayBlockingQueue数组有界阻塞队列一把锁LinkedBlockingQueue链表无界 / 有界读写分离两把锁并发高SynchronousQueue无容量插入必须等待取出PriorityBlockingQueue优先级阻塞队列DelayQueue延迟队列定时任务底层2. 并发 MapHashMap线程不安全并发 put 会链表循环死循环Hashtable全表 synchronized性能极差ConcurrentHashMap推荐分段锁 / 数组 CASsynchronized高并发安全JDK7分段 Segment 锁JDK8取消分段数组节点 CAS链表转红黑树锁只锁头节点3. 其他并发集合CopyOnWriteArrayList/CopyOnWriteArraySet写时复制读无锁写加锁复制新数组读多写少场景九、并发常见问题1. 死锁四个必要条件互斥资源独占持有并等待持有 A等待 B不可剥夺资源不能强制抢走循环等待线程 1 等线程 2 资源线程 2 等线程 1 资源解决死锁破坏任一条件统一锁获取顺序、设置超时、避免嵌套锁2. 线程安全总结不安全场景多线程读写共享变量无同步措施 安全方案优先级无共享栈局部变量不可变对象 final原子类 CASLock 锁synchronized十、并发工具完整使用场景总结表格工具用途volatile状态标记、DCL 单例synchronized简单同步、少量竞争ReentrantLock公平锁、可中断、多条件ReadWriteLock读多写少缓存AtomicXXX单个变量原子计数LongAdder高并发统计CountDownLatch等待多线程完成CyclicBarrier多线程同步等待Semaphore接口限流ThreadPoolExecutor异步任务执行ConcurrentHashMap高并发键值存储BlockingQueue生产者消费者十一、并发编程最佳实践尽量缩小同步代码块范围降低锁持有时间优先使用局部变量、不可变对象避免共享高并发计数用 LongAdder 代替 AtomicLong生产禁止 Executors 快捷创建线程池手动定义 ThreadPoolExecutorLock 锁必须放在 try-finally 中释放双重检查单例必须加 volatile避免嵌套锁防止死锁线程池合理设置核心线程、队列长度自定义拒绝策略读多写少场景使用 CopyOnWrite、读写锁不依赖线程优先级、yield调度不可控