Java基础之JUC与JMM

要理解 Java 并发编程,必须掌握JMM(Java Memory Model,Java 内存模型)JUC(java.util.concurrent,并发工具包) 这两个核心概念。JMM 是底层规范,定义了多线程交互的规则;JUC 是基于 JMM 实现的高层工具,简化了并发编程。下面分别详解:

一、JMM(Java Memory Model):多线程通信的底层规范

JMM 是抽象的内存模型 ,它并不直接对应物理硬件(如 CPU 缓存、主内存),而是定义了一套规则,用于规范线程如何通过内存进行交互,解决多线程环境下可见性、有序性、原子性问题。

1. JMM 的核心目标

多线程并发时,线程间的通信(数据共享)依赖于内存。JMM 的目标是:

  • 定义线程和主内存之间的交互方式(线程如何读取 / 写入内存);
  • 解决因 CPU 缓存、指令重排序等硬件 / 编译器优化导致的多线程数据不一致问题。

2. JMM 的核心结构

JMM 抽象了 "主内存" 和 "线程工作内存" 两个概念:

  • 主内存:所有线程共享的内存区域,存储共享变量(实例字段、静态字段等)。

  • 线程工作内存:每个线程私有的内存区域,存储主内存中共享变量的副本。线程对变量的读写操作,需先将变量从主内存加载到工作内存,修改后再同步回主内存。

(注意:这是逻辑抽象,并非物理上的内存划分,实际对应 CPU 缓存、寄存器等硬件)

3. JMM 解决的三大问题

多线程并发的核心问题是可见性、有序性、原子性,JMM 通过规则和关键字保证这些特性:

(1)可见性(Visibility)

问题 :线程 A 修改了共享变量,线程 B 可能无法立即看到最新值(因工作内存未同步到主内存)。
解决

  • volatile:强制变量读写直接操作主内存,通过 CPU 缓存一致性协议(如 MESI)通知其他线程缓存失效。
  • synchronized/Lock:解锁前必须将变量同步回主内存,加锁时必须从主内存加载最新值。
  • final:被final修饰的变量初始化后不可修改,一旦初始化完成,其他线程可见。
(2)有序性(Ordering)

问题 :编译器或 CPU 为优化性能,可能对指令重排序(单线程不影响结果,但多线程可能出错)。
解决

  • volatile:通过插入内存屏障(Memory Barrier)禁止重排序(写后加 "Store 屏障",读前加 "Load 屏障")。
  • synchronized/Lock:同步块内的指令视为一个整体,不会与块外指令重排序。
  • Happens-Before 规则 :JMM 定义的天然有序性规则,无需显式同步(如 "程序顺序规则":单线程内代码按顺序执行;"volatile 规则":volatile写操作先于读操作)。
(3)原子性(Atomicity)

问题 :一个操作(如i++)若包含多个步骤(读 - 改 - 写),多线程并发时可能被打断,导致结果错误。
解决

  • synchronized/Lock:通过排他锁保证同步块内操作的原子性(同一时间只有一个线程执行)。
  • 原子类(如AtomicInteger):基于 CPU 的 CAS(Compare-And-Swap)指令,实现无锁原子操作。

4. 关键:Happens-Before 规则

JMM 通过 "Happens-Before" 规则定义两个操作的执行顺序,无需显式同步即可保证有序性:

  • 程序顺序规则:单线程内,前面的操作 Happens-Before 后面的操作。
  • volatile 规则:volatile变量的写操作 Happens-Before 后续的读操作。
  • 锁规则:解锁操作 Happens-Before 后续的加锁操作。
  • 线程启动规则:Thread.start()Happens-Before 线程内的所有操作。
  • 线程终止规则:线程内的所有操作 Happens-Before 其他线程检测到该线程终止(如Thread.join()返回)。

二、JUC(java.util.concurrent):并发编程工具包

JUC 是 Java 5 引入的并发工具类库,基于 JMM 的规则实现,封装了复杂的并发逻辑,简化了多线程编程。核心组件包括:

1. 线程池(Executor 框架)

线程的创建 / 销毁成本高,线程池通过复用线程提高性能,核心类:

  • ExecutorService:线程池接口,定义了提交任务的方法(如submit())。
  • ThreadPoolExecutor:线程池核心实现类,可自定义核心线程数、最大线程数、队列等参数。
  • 工具类Executors:提供快捷创建线程池的方法(如newFixedThreadPool()newCachedThreadPool()),但实际开发中建议手动创建ThreadPoolExecutor以避免资源耗尽风险。

2. 并发集合(线程安全的集合)

解决HashMapArrayList等线程不安全集合的并发问题:

  • ConcurrentHashMap:线程安全的HashMap,Java 8 后基于 CAS+synchronized 实现,支持高并发读写。
  • CopyOnWriteArrayList:读操作无锁,写操作复制一份新数组修改后替换旧数组,适合读多写少场景。
  • ConcurrentLinkedQueue:无锁的并发队列,基于 CAS 实现,高效支持多线程入队 / 出队。
  • BlockingQueue:阻塞队列(如ArrayBlockingQueueLinkedBlockingQueue),常用于生产者 - 消费者模型(队列为空时读阻塞,满时写阻塞)。

3. 同步工具类

用于协调多线程的执行顺序:

  • CountDownLatch:倒计时门闩,让主线程等待多个子线程完成后再执行(countDown()减计数,await()阻塞等待计数为 0)。
  • CyclicBarrier:循环屏障,让多个线程到达屏障点后再一起继续执行(可重复使用,适合多轮协作)。
  • Semaphore:信号量,限制同时访问资源的线程数(acquire()获取许可,release()释放许可)。
  • Phaser:阶段同步器,支持动态调整参与线程数,适合分阶段的任务协作。

4. 原子操作类(java.util.concurrent.atomic)

基于 CAS 实现无锁原子操作,避免synchronized的性能开销:

  • 基本类型:AtomicIntegerAtomicLongAtomicBoolean(支持getAndIncrement()等原子操作)。
  • 引用类型:AtomicReference(原子更新对象引用)。
  • 数组类型:AtomicIntegerArray(原子更新数组元素)。
  • 字段更新器:AtomicIntegerFieldUpdater(原子更新对象的某个字段,需字段为volatile)。

5. 锁框架(java.util.concurrent.locks)

补充synchronized的不足,提供更灵活的锁机制:

  • Lock接口:定义锁的基本操作(lock()unlock()tryLock()等),实现类有:

    • ReentrantLock:可重入锁(支持公平锁 / 非公平锁,synchronized是隐式可重入)。
    • ReentrantReadWriteLock:读写锁,允许多个读线程并发,写线程独占(读多写少场景优化性能)。
  • Condition:与Lock配合使用,实现类似Object.wait()/notify()的等待 - 通知机制,支持多条件队列。

6. 其他工具

  • ThreadLocalRandom:线程安全的随机数生成器,比Random性能更高。
  • Fork/Join框架:基于分治思想的并行计算框架(ForkJoinPoolRecursiveTask),适合处理大任务拆分后的并行计算。

三、JMM 与 JUC 的关系

  • JMM 是基础:定义了多线程内存交互的规则(可见性、有序性、原子性),是所有并发机制的理论依据。

  • JUC 是实现 :JUC 中的工具类(如ReentrantLockAtomicInteger)均基于 JMM 的规则实现,例如:

    • volatile依赖 JMM 的可见性和有序性保证;
    • ReentrantLock通过 AQS(AbstractQueuedSynchronizer)框架,结合 JMM 的内存屏障和 CAS 操作实现同步;
    • 并发集合通过synchronizedLock或 CAS 保证线程安全,底层依赖 JMM 的原子性和可见性规则。

总结

  • JMM:解决 "多线程如何安全通信" 的底层规范,核心是通过规则保证可见性、有序性、原子性,是并发编程的 "宪法"。

  • JUC:基于 JMM 实现的 "工具箱",封装了线程池、并发集合、锁等工具,让开发者无需深入底层即可写出安全高效的并发代码。

掌握两者的关系,能帮助你从本质理解 Java 并发机制,避免 "只会用 API,不懂原理" 的困境。

相关推荐
C4程序员20 分钟前
北京JAVA基础面试30天打卡08
java·开发语言·面试
货拉拉技术28 分钟前
XXL-JOB参数错乱根因剖析:InheritableThreadLocal在多线程下的隐藏危机
java·分布式·后端
桃源学社(接毕设)37 分钟前
基于Django珠宝购物系统设计与实现(LW+源码+讲解+部署)
人工智能·后端·python·django·毕业设计
God-Hrh38 分钟前
JVM运维
java·开发语言·jvm
Hilaku39 分钟前
从“高级”到“资深”,我卡了两年和我的思考
前端·javascript·面试
鹿导的通天塔39 分钟前
高级RAG 00:检索增强生成(RAG)简介
人工智能·后端
xuejianxinokok1 小时前
解惑rust中的 Send/Sync(译)
后端·rust
Siler1 小时前
Oracle利用数据泵进行数据迁移
后端
mjy_1111 小时前
Linux下的软件编程——文件IO
java·linux·运维
用户6757049885021 小时前
3分钟,手摸手教你用OpenResty搭建高性能隧道代理(附完整配置!)
后端