Java并发锁与缓存实战核心总结
本文整合日常开发、面试高频的Java锁机制 、本地/分布式缓存选型 、缓存经典问题 、布隆过滤器核心知识点,剔除冗余内容,只保留实战可用、面试必背的干货,适合收藏复习。
一、Java核心锁机制(开发高频)
1. synchronized(内置锁,优先使用)
JVM层面实现的监视器锁,基于对象头MarkWord,是日常开发首选锁。
-
锁升级机制 :偏向锁 → 轻量级锁(CAS自旋)→ 重量级锁(OS阻塞),只升级、不降级
-
核心特性:默认非公平锁、自动释放锁(代码执行完毕/异常自动解锁)、支持可重入
-
短板:不支持公平锁、锁中断、非阻塞尝试获取锁、多条件等待唤醒
-
底层原理:依赖Monitor监视器,内置唯一的wait/notify等待队列
-
注意:锁的是对象,锁对象发生变更,锁直接失效
2. ReentrantLock(可重入显式锁)
JDK代码层面实现,基于AQS抽象队列同步器,弥补synchronized的功能短板。
-
AQS核心:volatile int state(记录锁状态/重入次数)+ CLH双向等待队列 + LockSupport线程阻塞唤醒
-
核心优势:支持公平/非公平锁、lockInterruptibly()可中断锁、tryLock()非阻塞抢锁、多Condition条件队列
-
强制规范:必须手动unlock,且写在finally中;重入时lock和unlock次数必须严格一致
-
适用场景:需要灵活锁控制、排队任务、高并发降级兜底的场景
3. ReentrantReadWriteLock(读写锁,极少手写)
基于AQS实现,拆分读写锁,核心规则:读共享、写独占。
-
AQS state拆分:高16位=读锁计数,低16位=写锁重入次数
-
锁升降级规则(高频面试)
-
读锁→写锁(升级):禁止,多线程持有读锁互相等待,引发死锁
-
写锁→读锁(降级):允许,单线程独占写锁,无并发冲突,可保证数据一致性
-
-
致命缺陷:存在写饥饿问题,大量读锁阻塞写线程
-
开发建议:业务代码极少手写,仅框架底层使用;业务读多写少场景优先用ConcurrentHashMap
锁选型终极口诀
-
简单同步场景:优先 synchronized(简洁安全,无死锁风险)
-
需要高级锁特性(公平/中断/tryLock/多条件):用ReentrantLock
-
杜绝手写读写锁,避免踩坑
二、三级缓存实战选型(业务核心)
缓存核心作用
将高频读取、低频变更 的数据从慢速数据库磁盘IO,转移到高速内存读写,核心价值:提升接口响应速度、大幅减轻数据库压力。
本质取舍:牺牲短暂数据一致性,换取极致性能。
1. ConcurrentHashMap(简易本地缓存)
JDK原生线程安全Map,无第三方依赖,适合极简临时缓存场景。
-
核心特性:单个方法(get/put/remove/putIfAbsent)原子安全
-
致命短板 :不支持复合操作原子性(如containsKey+put组合会并发出错)、无过期淘汰策略、易内存溢出
-
适用场景:少量、几乎不变、无需过期的临时配置数据
2. Caffeine(生产级本地缓存)
目前Java最优本地缓存框架,底层基于ConcurrentHashMap,企业项目标配。
-
核心能力:支持TTL过期、LRU容量淘汰、自动回源加载数据、命中率统计
-
特性 :JVM本地缓存,服务重启数据丢失、多实例数据不共享
-
适用场景:系统字典、全局配置、本地热点数据缓存
3. Redis(分布式缓存)
独立中间件,分布式项目必备缓存方案。
-
核心特性:多服务实例全局共享数据、支持持久化、TTL过期、高可用集群
-
短板:存在网络IO,速度慢于本地内存缓存
-
适用场景:多实例部署、需要全局数据一致、需持久化的热点业务数据
企业主流架构:双层缓存(Caffeine + Redis)
执行流程:本地Caffeine缓存 → Redis分布式缓存 → MySQL数据库
优势:规避Redis网络开销,极致提速,同时保证多实例数据最终一致
缓存更新规范 :数据库更新后,直接删除缓存(不更新缓存),靠TTL过期兜底一致性,避免并发脏数据
三、缓存三大经典问题(面试必问)
1. 缓存穿透
现象:查询数据库不存在的非法数据,缓存无数据,所有请求直接打穿到DB,恶意攻击可压垮数据库。
解决方案 :普通场景缓存空值;海量数据场景使用布隆过滤器拦截非法key。
2. 缓存击穿
现象 :单个热点key缓存过期,瞬间海量并发请求直接打到DB。
解决方案:热点key永不过期、加分布式互斥锁(单线程回源查DB)。
3. 缓存雪崩
现象:大量缓存key同时过期 / Redis集群宕机,批量请求集中打垮DB。
解决方案:缓存过期时间加随机值打散、Redis高可用部署、接口限流降级。
四、布隆过滤器核心原理
专门解决海量数据缓存穿透的工具,核心能力:快速判断数据是否存在。
1. 底层结构
超大比特数组(仅存储0/1)+ 多个不同哈希函数,内存占用极低。
2. 工作流程
-
添加数据:多哈希函数计算多个数组下标,对应位置全部置1
-
查询数据 :任意下标为0 → 数据一定不存在 ;所有下标为1 → 数据可能存在(假阳性)
3. 核心优缺点
-
优点:查询速度快、海量数据内存占用极小
-
缺点:存在假阳性误判、不支持删除数据
4. 工程使用
单机场景用Guava布隆过滤器,分布式场景用Redis布隆过滤器,无需手动实现。
五、最终开发选型总结
-
锁选型:普通并发用synchronized,复杂锁控制用ReentrantLock,杜绝手写读写锁
-
本地缓存:简单临时数据用ConcurrentHashMap,生产正式缓存用Caffeine
-
分布式缓存:多实例共享数据、需持久化统一数据,用Redis
-
缓存问题:穿透用空值/布隆过滤器,击穿用锁/永不过期,雪崩用过期打散+限流