Java锁全面指南:从基础概念到企业级应用
目录
- 锁的基本概念
- Java中的锁分类
- synchronized关键字
- ReentrantLock
- 读写锁ReadWriteLock
- StampedLock
- CAS与原子类
- 并发容器中的锁
- 分布式锁
- 锁的性能优化
- 企业级应用场景
- 最佳实践与常见问题
锁的基本概念
什么是锁?
锁是多线程编程中用于控制对共享资源访问的同步机制。当多个线程同时访问共享资源时,锁可以确保同一时刻只有一个线程能够执行临界区代码,从而避免数据竞争和不一致性问题。
为什么需要锁?
public class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
锁的核心特性
| 特性 | 说明 |
|---|
| 互斥性 | 同一时刻只有一个线程能持有锁 |
| 可见性 | 一个线程释放锁后,其他线程能看到其修改 |
| 有序性 | 保证程序执行的顺序性 |
| 原子性 | 确保操作的原子性 |
Java中的锁分类
按乐观/悲观分类
锁分类
├── 悲观锁 (Pessimistic Lock)
│ ├── synchronized
│ ├── ReentrantLock
│ └── 数据库行锁/表锁
│
└── 乐观锁 (Optimistic Lock)
├── CAS操作
├── 版本号机制
└── 数据库乐观锁
按公平性分类
公平性
├── 公平锁 (Fair Lock)
│ └── 按线程请求顺序获取锁
│
└── 非公平锁 (Unfair Lock)
└── 允许插队,性能更好
按可重入性分类
可重入性
├── 可重入锁 (Reentrant Lock)
│ └── 同一线程可多次获取同一把锁
│
└── 不可重入锁 (Non-reentrant Lock)
└── 同一线程再次获取会死锁
synchronized关键字
基本用法
public class SynchronizedDemo {
public synchronized void method1() {
}
public static synchronized void method2() {
}
public void method3() {
synchronized (this) {
}
}
public void method4() {
synchronized (SynchronizedDemo.class) {
}
}
}
底层原理
synchronized执行流程
┌─────────────────────────────────────────────────────────┐
│ synchronized代码块 │
├─────────────────────────────────────────────────────────┤
│ monitorenter指令 ──→ 获取Monitor对象 ──→ 进入同步块 │
├─────────────────────────────────────────────────────────┤
│ 执行同步代码 │
├─────────────────────────────────────────────────────────┤
│ monitorexit指令 ──→ 释放Monitor对象 ──→ 退出同步块 │
└─────────────────────────────────────────────────────────┘
synchronized的优化历程
Java版本优化
├── JDK 1.6之前
│ └── 纯粹的重量级锁(依赖操作系统Mutex Lock)
│
├── JDK 1.6
│ ├── 偏向锁 (Biased Locking)
│ ├── 轻量级锁 (Lightweight Lock)
│ ├── 重量级锁 (Heavyweight Lock)
│ └── 自旋锁 (Spin Lock)
│
└── 锁升级过程
无锁 → 偏向锁 → 轻量级锁 → 重量级锁
锁升级详解
ReentrantLock
基本用法
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
private final ReentrantLock lock = new ReentrantLock();
public void safeMethod() {
lock.lock();
try {
} finally {
lock.unlock();
}
}
}
高级特性
public class ReentrantLockAdvanced {
private final ReentrantLock lock = new ReentrantLock();
public void interruptibleMethod() throws InterruptedException {
lock.lockInterruptibly();
try {
} finally {
lock.unlock();
}
}
public void tryLockMethod() {
if (lock.tryLock()) {
try {
} finally {
lock.unlock();
}
} else {
}
}
public void timedLockMethod() throws InterruptedException {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
} finally {
lock.unlock();
}
} else {
}
}
public ReentrantLock fairLock() {
return new ReentrantLock(true);
}
public void conditionMethod() throws InterruptedException {
Condition condition = lock.newCondition();
lock.lock();
try {
while () {
condition.await();
}
} finally {
lock.unlock();
}
}
public void signalMethod() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
ReentrantLock vs synchronized
| 特性 | ReentrantLock | synchronized |
|---|
| 可中断 | 支持 | 不支持 |
| 超时获取 | 支持 | 不支持 |
| 公平性 | 可选 | 非公平 |
| 条件变量 | 多个Condition | 只有一个wait/notify |
| 性能 | JDK 6+后差不多 | JDK 6+后优化 |
| 锁释放 | 必须手动释放 | 自动释放 |
读写锁ReadWriteLock
基本概念
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private Map<String, Object> cache = new HashMap<>();
public Object read(String key) {
readLock.lock();
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}
public void write(String key, Object value) {
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
}
读写锁的state设计
ReentrantReadWriteLock的state (int类型,32位)
├── 高16位:记录读锁持有次数
└── 低16位:记录写锁重入次数
锁降级与锁升级
public void lockDowngrade() {
writeLock.lock();
try {
readLock.lock();
} finally {
writeLock.unlock();
}
try {
} finally {
readLock.unlock();
}
}
StampedLock
三种模式
import java.util.concurrent.locks.StampedLock;
public class StampedLockDemo {
private final StampedLock sl = new StampedLock();
private double x, y;
public void move(double deltaX, double deltaY) {
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
public double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead();
double currentX = x, currentY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
public void readOnly() {
long stamp = sl.readLock();
try {
} finally {
sl.unlockRead(stamp);
}
}
}
StampedLock vs ReadWriteLock
| 特性 | StampedLock | ReadWriteLock |
|---|
| 乐观读 | 支持 | 不支持 |
| 性能 | 更高 | 较低 |
| 可重入 | 不支持 | 支持 |
| Condition | 不支持 | 支持 |
| 公平性 | 不支持 | 可选 |
CAS与原子类
CAS原理
CAS (Compare-And-Swap)
┌─────────────────────────────────────────────────────────┐
│ 比较内存中的值与期望值 │
│ 如果相等,则更新为新值 │
│ 否则,什么都不做 │
└─────────────────────────────────────────────────────────┘
三个操作数:
- V: 内存地址(要更新的变量)
- E: 期望值(旧值)
- N: 新值(要写入的值)
if (V == E) {
V = N;
return true;
} else {
return false;
}
原子类
import java.util.concurrent.atomic.*;
public class AtomicDemo {
private AtomicInteger atomicInt = new AtomicInteger(0);
private AtomicReference<Object> atomicRef = new AtomicReference<>();
private AtomicIntegerArray atomicArray = new AtomicIntegerArray(10);
private AtomicIntegerFieldUpdater<User> userUpdater =
AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
public void atomicOperations() {
atomicInt.incrementAndGet();
atomicInt.compareAndSet(5, 10);
atomicInt.updateAndGet(x -> x * 2);
}
private LongAdder longAdder = new LongAdder();
public void add() {
longAdder.add(1);
}
public long sum() {
return longAdder.sum();
}
}
ABA问题
AtomicStampedReference<Integer> stampedRef =
new AtomicStampedReference<>(1, 0);
int stamp = stampedRef.getStamp();
Integer value = stampedRef.getReference();
stampedRef.compareAndSet(1, 2, stamp, stamp + 1);
并发容器中的锁
ConcurrentHashMap
public class ConcurrentHashMapDemo {
private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
public void safeOperations() {
map.put("key", "value");
map.putIfAbsent("key", "value");
map.compute("key", (k, v) -> v == null ? "default" : v);
map.merge("key", 1, (old, newVal) -> (int) old + (int) newVal);
}
}
其他并发容器
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
LinkedBlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
blockingQueue.put("item");
blockingQueue.take();
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();
分布式锁
基于Redis实现
import redis.clients.jedis.Jedis;
import java.util.UUID;
public class RedisDistributedLock {
private static final String LOCK_PREFIX = "lock:";
private static final long LOCK_EXPIRE = 30000;
private Jedis jedis;
private String lockKey;
private String lockValue;
private ThreadLocal<String> threadLocal = new ThreadLocal<>();
public boolean tryLock(String key) {
lockKey = LOCK_PREFIX + key;
lockValue = UUID.randomUUID().toString();
String result = jedis.set(lockKey, lockValue, "NX", "PX", LOCK_EXPIRE);
if ("OK".equals(result)) {
threadLocal.set(lockValue);
return true;
}
return false;
}
public boolean unlock() {
String script =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
Object result = jedis.eval(script,
Collections.singletonList(lockKey),
Collections.singletonList(threadLocal.get()));
return Long.valueOf(result.toString()) == 1;
}
}
基于ZooKeeper实现
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.concurrent.CountDownLatch;
public class ZookeeperDistributedLock {
private ZooKeeper zookeeper;
private String lockPath;
private CountDownLatch latch;
public void lock(String key) throws Exception {
lockPath = "/locks/" + key + "/" + System.nanoTime();
zookeeper.create(lockPath, new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
while (true) {
Stat stat = new Stat();
byte[] data = zookeeper.getData("/locks/" + key, false, stat);
List<String> children = zookeeper.getChildren("/locks/" + key, false);
Collections.sort(children);
if (lockPath.endsWith(children.get(0))) {
return;
}
latch = new CountDownLatch(1);
Stat watchStat = zookeeper.exists("/locks/" + key + "/" +
children.get(children.indexOf(lockPath.replace("/locks/" + key + "/", "")) - 1),
event -> {
if (event.getType() == Watcher.Event.EventType.NodeDeleted) {
latch.countDown();
}
});
if (watchStat != null) {
latch.await();
}
}
}
public void unlock() throws Exception {
zookeeper.delete(lockPath, -1);
}
}
基于数据库实现
CREATE TABLE distributed_lock (
lock_key VARCHAR(255) PRIMARY KEY,
lock_value VARCHAR(255) NOT NULL,
expire_time DATETIME NOT NULL,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO distributed_lock (lock_key, lock_value, expire_time)
VALUES ('order_lock', 'uuid_value', DATE_ADD(NOW(), INTERVAL 30 SECOND))
ON DUPLICATE KEY UPDATE
lock_value = IF(expire_time < NOW(), VALUES(lock_value), lock_value),
expire_time = IF(expire_time < NOW(), VALUES(expire_time), expire_time);
DELETE FROM distributed_lock
WHERE lock_key = 'order_lock' AND lock_value = 'uuid_value';
分布式锁对比
| 实现方式 | 优点 | 缺点 | 适用场景 |
|---|
| Redis | 性能高,实现简单 | 需要处理主从同步 | 高并发、低延迟 |
| ZooKeeper | 可靠性高,支持公平锁 | 性能较低 | 强一致性要求 |
| 数据库 | 实现简单,易于理解 | 性能最低 | 低并发场景 |
锁的性能优化
1. 减少锁持有时间
public void badPractice() {
lock.lock();
try {
doSomethingUnnecessary();
doCriticalSection();
doSomethingElse();
} finally {
lock.unlock();
}
}
public void goodPractice() {
doSomethingUnnecessary();
lock.lock();
try {
doCriticalSection();
} finally {
lock.unlock();
}
doSomethingElse();
}
2. 降低锁粒度
public class CoarseLock {
private final Object lock = new Object();
private Map<String, Object> map = new HashMap<>();
public void put(String key, Object value) {
synchronized (lock) {
map.put(key, value);
}
}
}
public class FineLock {
private Map<String, Object> map = new ConcurrentHashMap<>();
public void put(String key, Object value) {
map.put(key, value);
}
}
3. 使用读写锁
public class ReadWriteOptimization {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private Map<String, Object> data = new HashMap<>();
public Object read(String key) {
readLock.lock();
try {
return data.get(key);
} finally {
readLock.unlock();
}
}
public void write(String key, Object value) {
writeLock.lock();
try {
data.put(key, value);
} finally {
writeLock.unlock();
}
}
}
4. 使用乐观锁
public class LockFreeOptimization {
private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet();
}
private LongAdder longAdder = new LongAdder();
public void add() {
longAdder.add(1);
}
}
5. 避免锁嵌套
public void nestedLocks() {
lockA.lock();
try {
lockB.lock();
try {
} finally {
lockB.unlock();
}
} finally {
lockA.unlock();
}
}
public void avoidNestedLocks() {
lockA.lock();
try {
} finally {
lockA.unlock();
}
lockB.lock();
try {
} finally {
lockB.unlock();
}
}
企业级应用场景
1. 订单号生成
@Service
public class OrderService {
@Autowired
private RedisDistributedLock redisLock;
@Autowired
private OrderMapper orderMapper;
public String generateOrderNo() {
String lockKey = "order_no_lock";
boolean locked = redisLock.tryLock(lockKey);
try {
if (locked) {
String maxOrderNo = orderMapper.getMaxOrderNo();
return generateNextOrderNo(maxOrderNo);
} else {
throw new RuntimeException("获取锁失败");
}
} finally {
if (locked) {
redisLock.unlock();
}
}
}
private String generateNextOrderNo(String maxOrderNo) {
if (maxOrderNo == null) {
return "ORD" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "000001";
}
String datePart = maxOrderNo.substring(3, 11);
int seq = Integer.parseInt(maxOrderNo.substring(11)) + 1;
return "ORD" + datePart + String.format("%06d", seq);
}
}
2. 库存扣减
@Service
public class StockService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String DEDUCT_SCRIPT =
"local stock = tonumber(redis.call('get', KEYS[1])) " +
"if stock and stock >= tonumber(ARGV[1]) then " +
" redis.call('decrby', KEYS[1], ARGV[1]) " +
" return 1 " +
"else " +
" return 0 " +
"end";
public boolean deductStock(String skuId, int quantity) {
Long result = redisTemplate.execute(
new DefaultRedisScript<>(DEDUCT_SCRIPT, Long.class),
Collections.singletonList("stock:" + skuId),
String.valueOf(quantity)
);
return result != null && result == 1;
}
@Transactional
public boolean deductStockWithDB(String skuId, int quantity) {
int version = stockMapper.getVersion(skuId);
int rows = stockMapper.deductStock(skuId, quantity, version);
return rows > 0;
}
}
3. 缓存击穿防护
@Service
public class CacheService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private ReentrantLock lock = new ReentrantLock();
public Object getData(String key) {
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
lock.lock();
try {
value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
value = loadFromDB(key);
redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
return value;
} finally {
lock.unlock();
}
}
public Object getDataWithDistributedLock(String key) {
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
String lockKey = "lock:" + key;
boolean locked = distributedLock.tryLock(lockKey);
try {
if (locked) {
value = loadFromDB(key);
redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
return value;
} else {
Thread.sleep(100);
return redisTemplate.opsForValue().get(key);
}
} finally {
if (locked) {
distributedLock.unlock();
}
}
}
}
4. 分布式任务调度
@Service
public class TaskScheduler {
@Autowired
private ZookeeperDistributedLock zkLock;
public void executeTask(String taskId) {
String lockKey = "task_lock_" + taskId;
try {
zkLock.lock(lockKey);
doTask(taskId);
} catch (Exception e) {
log.error("任务执行失败", e);
} finally {
try {
zkLock.unlock();
} catch (Exception e) {
log.error("释放锁失败", e);
}
}
}
private void doTask(String taskId) {
}
}
5. 接口限流
@Component
public class RateLimiter {
private final LoadingCache<String, AtomicInteger> counterCache;
public RateLimiter() {
counterCache = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS)
.build(new CacheLoader<String, AtomicInteger>() {
@Override
public AtomicInteger load(String key) {
return new AtomicInteger(0);
}
});
}
public boolean isAllowed(String key, int maxRequests) {
try {
AtomicInteger counter = counterCache.get(key);
int current = counter.incrementAndGet();
return current <= maxRequests;
} catch (ExecutionException e) {
return false;
}
}
public boolean isAllowedWithRedis(String key, int maxRequests, int windowSeconds) {
String redisKey = "rate:" + key;
Long count = redisTemplate.opsForValue().increment(redisKey);
if (count == 1) {
redisTemplate.expire(redisKey, windowSeconds, TimeUnit.SECONDS);
}
return count != null && count <= maxRequests;
}
}
最佳实践与常见问题
最佳实践
lock.lock();
try {
} finally {
lock.unlock();
}
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
} finally {
lock.unlock();
}
} else {
}
synchronized (lock) {
}
常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|
| 死锁 | 锁顺序不一致 | 固定锁顺序,使用tryLock |
| 活锁 | 线程一直重试 | 添加随机延迟 |
| 饥饿 | 低优先级线程无法获取锁 | 使用公平锁 |
| 性能下降 | 锁粒度太粗 | 降低锁粒度,使用读写锁 |
| 缓存击穿 | 热点数据过期 | 使用互斥锁或逻辑过期 |
锁选择指南
选择锁的决策流程
├── 单机环境
│ ├── 简单同步 → synchronized
│ ├── 需要超时/中断 → ReentrantLock
│ ├── 读多写少 → ReadWriteLock
│ ├── 高并发读 → StampedLock
│ └── 无锁优先 → 原子类
│
└── 分布式环境
├── 高性能要求 → Redis分布式锁
├── 高可靠性要求 → ZooKeeper分布式锁
└── 简单场景 → 数据库分布式锁
总结
Java锁机制是并发编程的核心,理解各种锁的特性和适用场景对于编写高质量的并发程序至关重要。在实际应用中,应该:
- 根据场景选择合适的锁:单机环境优先考虑JDK内置锁,分布式环境使用分布式锁
- 优化锁的使用:减小锁粒度、缩短持有时间、避免锁嵌套
- 注意性能和安全性平衡:不要过度优化,也不要忽视潜在的并发问题
- 充分测试:使用压力测试验证锁的正确性和性能
掌握这些知识,你将能够在企业级应用中游刃有余地处理各种并发场景。