第477集分布式锁的正确用法与误区?
|字数总计:5.5k|阅读时长:23分钟|阅读量:
分布式锁的正确用法与误区?
1. 概述
1.1 分布式锁的重要性
分布式锁是分布式系统设计的核心组件之一,用于在分布式环境下保证资源的互斥访问。
分布式锁的应用场景:
- 防止重复操作:防止重复支付、重复下单等
- 资源互斥访问:保证同一时间只有一个请求能访问共享资源
- 分布式任务调度:保证定时任务只在一个节点执行
- 缓存更新:防止缓存击穿、缓存雪崩
1.2 分布式锁的挑战
分布式锁的挑战:
- 死锁问题:锁未正确释放导致死锁
- 锁超时问题:锁超时时间设置不当
- 锁续期问题:长时间任务需要锁续期
- 性能问题:锁成为性能瓶颈
- 可用性问题:锁服务故障导致系统不可用
1.3 本文内容结构
本文将从以下几个方面全面解析分布式锁:
- 分布式锁原理:什么是分布式锁、为什么需要分布式锁
- 实现方式:Redis、ZooKeeper、数据库等实现方式
- 正确用法:正确的使用方式和最佳实践
- 常见误区:常见错误和如何避免
- 实战案例:实际项目中的分布式锁使用
2. 分布式锁原理
2.1 什么是分布式锁
2.1.1 定义
分布式锁:在分布式环境下,用于保证同一时间只有一个进程或线程能访问共享资源的机制。
特点:
- 互斥性:同一时间只有一个进程能持有锁
- 可重入性:同一进程可以多次获取锁
- 锁超时:锁有超时时间,防止死锁
- 高可用:锁服务需要高可用
2.1.2 与本地锁的区别
本地锁(synchronized、ReentrantLock):
- 只作用于单个JVM进程
- 不能跨进程、跨机器
- 性能高,无网络开销
分布式锁:
- 作用于多个JVM进程
- 可以跨进程、跨机器
- 性能较低,有网络开销
2.2 为什么需要分布式锁
2.2.1 分布式环境下的问题
问题场景:
- 多实例部署:应用部署在多个节点
- 共享资源:多个节点访问共享资源(数据库、缓存等)
- 并发访问:多个请求同时访问共享资源
示例:
- 用户下单,多个实例同时处理,可能导致重复下单
- 定时任务,多个实例同时执行,可能导致重复执行
2.2.2 分布式锁的作用
分布式锁的作用:
- 保证互斥:同一时间只有一个请求能执行
- 防止重复:防止重复操作
- 保证一致性:保证数据一致性
3. 分布式锁实现方式
3.1 Redis分布式锁
3.1.1 基本原理
Redis分布式锁:使用Redis的SET命令实现分布式锁。
实现原理:
- 使用
SET key value NX EX timeout命令
NX:只在键不存在时设置
EX:设置过期时间
- 释放锁时删除键
3.1.2 基础实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @Service public class RedisDistributedLock { @Autowired private StringRedisTemplate redisTemplate;
public boolean tryLock(String lockKey, String lockValue, long expireTime, TimeUnit timeUnit) { Boolean result = redisTemplate.opsForValue().setIfAbsent( lockKey, lockValue, expireTime, timeUnit ); return Boolean.TRUE.equals(result); }
public void unlock(String lockKey, String lockValue) { String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " + " return redis.call('del', KEYS[1]) " + "else " + " return 0 " + "end"; DefaultRedisScript<Long> script = new DefaultRedisScript<>(); script.setScriptText(luaScript); script.setResultType(Long.class); redisTemplate.execute(script, Collections.singletonList(lockKey), lockValue); } }
|
3.1.3 Redisson实现(推荐)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Service public class RedissonDistributedLock { @Autowired private RedissonClient redissonClient;
public boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit timeUnit) { RLock lock = redissonClient.getLock(lockKey); try { return lock.tryLock(waitTime, leaseTime, timeUnit); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } }
public void unlock(String lockKey) { RLock lock = redissonClient.getLock(lockKey); if (lock.isHeldByCurrentThread()) { lock.unlock(); } }
public void doSomething(String lockKey) { RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doBusinessLogic(); } finally { lock.unlock(); } } else { throw new BusinessException("获取锁失败"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } } }
|
3.2 ZooKeeper分布式锁
3.2.1 基本原理
ZooKeeper分布式锁:使用ZooKeeper的临时顺序节点实现分布式锁。
实现原理:
- 创建临时顺序节点
- 获取所有子节点,判断自己是否是最小节点
- 如果是,获取锁;否则,监听前一个节点
- 释放锁时删除节点
3.2.2 实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Service public class ZooKeeperDistributedLock { @Autowired private CuratorFramework curatorFramework; private static final String LOCK_PATH = "/distributed-lock";
public InterProcessMutex acquireLock(String lockKey) { String lockPath = LOCK_PATH + "/" + lockKey; InterProcessMutex mutex = new InterProcessMutex(curatorFramework, lockPath); return mutex; }
public void doSomething(String lockKey) { InterProcessMutex mutex = acquireLock(lockKey); try { if (mutex.acquire(10, TimeUnit.SECONDS)) { try { doBusinessLogic(); } finally { mutex.release(); } } else { throw new BusinessException("获取锁失败"); } } catch (Exception e) { throw new BusinessException("获取锁异常", e); } } }
|
3.3 数据库分布式锁
3.3.1 基本原理
数据库分布式锁:使用数据库的唯一索引或行锁实现分布式锁。
实现方式:
- 唯一索引:插入唯一记录作为锁
- 行锁:使用SELECT FOR UPDATE
3.3.2 实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| @Service public class DatabaseDistributedLock { @Autowired private DistributedLockMapper lockMapper;
public boolean tryLock(String lockKey, String lockValue, long expireTime) { try { DistributedLock lock = new DistributedLock(); lock.setLockKey(lockKey); lock.setLockValue(lockValue); lock.setExpireTime(LocalDateTime.now().plusSeconds(expireTime)); lockMapper.insert(lock); return true; } catch (DuplicateKeyException e) { DistributedLock existingLock = lockMapper.selectByLockKey(lockKey); if (existingLock != null && existingLock.getExpireTime().isBefore(LocalDateTime.now())) { lockMapper.deleteByLockKey(lockKey); return tryLock(lockKey, lockValue, expireTime); } return false; } }
public void unlock(String lockKey, String lockValue) { DistributedLock lock = lockMapper.selectByLockKey(lockKey); if (lock != null && lock.getLockValue().equals(lockValue)) { lockMapper.deleteByLockKey(lockKey); } }
@Transactional public boolean tryLockWithRowLock(String lockKey) { DistributedLock lock = lockMapper.selectForUpdate(lockKey); if (lock == null) { lock = new DistributedLock(); lock.setLockKey(lockKey); lock.setExpireTime(LocalDateTime.now().plusSeconds(30)); lockMapper.insert(lock); return true; } else if (lock.getExpireTime().isBefore(LocalDateTime.now())) { lock.setExpireTime(LocalDateTime.now().plusSeconds(30)); lockMapper.updateById(lock); return true; } return false; } }
|
4. 分布式锁的正确用法
4.1 基本使用模式
4.1.1 标准模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Service public class OrderService { @Autowired private RedissonClient redissonClient;
public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { lock.unlock(); } } else { throw new BusinessException("系统繁忙,请稍后再试"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } } }
|
4.1.2 关键要点
关键要点:
- 锁必须在finally中释放:确保锁一定会被释放
- 检查锁的持有者:释放锁前检查是否是当前线程持有
- 设置合理的超时时间:避免死锁
- 处理中断异常:正确处理InterruptedException
4.2 锁超时时间设置
4.2.1 超时时间的重要性
超时时间的作用:
- 防止死锁:锁超时后自动释放
- 保证可用性:避免锁一直占用资源
设置原则:
- 不能太短:业务逻辑未执行完就超时
- 不能太长:死锁时等待时间过长
4.2.2 动态超时时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Service public class OrderService { @Autowired private RedissonClient redissonClient;
public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, TimeUnit.MILLISECONDS)) { try { long startTime = System.currentTimeMillis(); doCreateOrder(request); long duration = System.currentTimeMillis() - startTime; long lockTimeout = Math.max(duration * 2, 30000); lock.expire(lockTimeout, TimeUnit.MILLISECONDS); } finally { lock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } } }
|
4.3 锁续期(Watch Dog)
4.3.1 锁续期的必要性
锁续期的场景:
- 长时间任务:业务逻辑执行时间超过锁超时时间
- 不确定执行时间:无法预估业务逻辑执行时间
Redisson的Watch Dog机制:
- 自动续期:锁超时时间的三分之一时自动续期
- 默认续期时间:30秒
4.3.2 使用Watch Dog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Service public class OrderService { @Autowired private RedissonClient redissonClient;
public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { lock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } } }
|
4.4 可重入锁
4.4.1 可重入锁的必要性
可重入锁的场景:
- 递归调用:方法内部递归调用
- 方法调用链:方法A调用方法B,都需要获取锁
Redisson的RLock:
4.4.2 使用可重入锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Service public class OrderService { @Autowired private RedissonClient redissonClient;
public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { validateOrder(request); processOrder(request); } finally { lock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } }
private void validateOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); if (lock.tryLock()) { try { } finally { lock.unlock(); } } } }
|
4.5 读写锁
4.5.1 读写锁的应用场景
读写锁的场景:
- 读多写少:读操作可以并发,写操作需要互斥
- 缓存更新:多个读操作可以并发,写操作需要互斥
4.5.2 使用读写锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| @Service public class CacheService { @Autowired private RedissonClient redissonClient;
public String getCache(String key) { String lockKey = "cache:lock:" + key; RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(lockKey); RLock readLock = readWriteLock.readLock(); try { if (readLock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { return getCacheFromRedis(key); } finally { readLock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return null; }
public void updateCache(String key, String value) { String lockKey = "cache:lock:" + key; RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(lockKey); RLock writeLock = readWriteLock.writeLock(); try { if (writeLock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { updateCacheToRedis(key, value); } finally { writeLock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
|
5. 分布式锁的常见误区
5.1 误区1:锁未在finally中释放
5.1.1 错误示例
1 2 3 4 5 6 7 8
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); if (lock.tryLock()) { doCreateOrder(request); lock.unlock(); } }
|
5.1.2 正确做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock()) { try { doCreateOrder(request); } finally { lock.unlock(); } } } catch (Exception e) { } }
|
5.2 误区2:释放了其他线程的锁
5.2.1 错误示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { lock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
|
5.2.2 正确做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
|
5.3 误区3:锁超时时间设置不当
5.3.1 错误示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 1, TimeUnit.SECONDS)) { try { doCreateOrder(request); } finally { lock.unlock(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
|
5.3.2 正确做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { long estimatedTime = estimateBusinessTime(request); long lockTimeout = Math.max(estimatedTime * 2, 30000); if (lock.tryLock(100, lockTimeout, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
|
5.4 误区4:未处理锁获取失败
5.4.1 错误示例
1 2 3 4 5 6 7 8 9 10
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); lock.lock(); try { doCreateOrder(request); } finally { lock.unlock(); } }
|
5.4.2 正确做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } else { throw new BusinessException("系统繁忙,请稍后再试"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } }
|
5.5 误区5:锁粒度太粗
5.5.1 错误示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
|
5.5.2 正确做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
|
5.6 误区6:未考虑锁服务故障
5.6.1 错误示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (Exception e) { } }
|
5.6.2 正确做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public void createOrder(OrderRequest request) { RLock lock = redissonClient.getLock("order:lock"); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doCreateOrder(request); } finally { try { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } catch (Exception e) { log.error("释放锁失败", e); } } } } catch (Exception e) { if (e instanceof RedisException) { return createOrderWithDatabaseLock(request); } throw e; } }
|
6. 实战案例
6.1 案例1:防止重复下单
6.1.1 场景
需求:防止用户重复下单,高并发场景。
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| @Service public class OrderService { @Autowired private RedissonClient redissonClient; @Autowired private OrderMapper orderMapper;
public OrderResult createOrder(OrderRequest request) { String lockKey = "order:create:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { Order existingOrder = orderMapper.selectByUserIdAndSkuId( request.getUserId(), request.getSkuId() ); if (existingOrder != null) { return OrderResult.success(existingOrder, "订单已存在"); } Order order = new Order(); order.setUserId(request.getUserId()); order.setSkuId(request.getSkuId()); order.setQuantity(request.getQuantity()); order.setAmount(request.getAmount()); order.setStatus(OrderStatus.PENDING); orderMapper.insert(order); return OrderResult.success(order); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } else { throw new BusinessException("系统繁忙,请稍后再试"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } } }
|
6.2 案例2:防止重复支付
6.2.1 场景
需求:防止订单重复支付,保证支付幂等性。
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| @Service public class PaymentService { @Autowired private RedissonClient redissonClient; @Autowired private PaymentRecordMapper paymentRecordMapper; @Autowired private OrderMapper orderMapper;
@Transactional public PaymentResult payOrder(Long orderId, BigDecimal amount) { String lockKey = "payment:lock:" + orderId; RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { Order order = orderMapper.selectById(orderId); if (order == null) { throw new BusinessException("订单不存在"); } if (order.getStatus() == OrderStatus.PAID) { PaymentRecord record = paymentRecordMapper.selectByOrderId(orderId); return PaymentResult.success(record, "订单已支付"); } if (order.getStatus() != OrderStatus.PENDING) { throw new BusinessException("订单状态不允许支付"); } if (order.getAmount().compareTo(amount) != 0) { throw new BusinessException("支付金额不匹配"); } PaymentRecord record = new PaymentRecord(); record.setOrderId(orderId); record.setAmount(amount); record.setStatus(PaymentStatus.SUCCESS); paymentRecordMapper.insert(record); int updated = orderMapper.updateStatusWithVersion( orderId, OrderStatus.PENDING, OrderStatus.PAID, order.getVersion() ); if (updated == 0) { order = orderMapper.selectById(orderId); if (order.getStatus() == OrderStatus.PAID) { record = paymentRecordMapper.selectByOrderId(orderId); return PaymentResult.success(record, "订单已支付"); } throw new BusinessException("订单状态已变更"); } return PaymentResult.success(record); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } else { throw new BusinessException("系统繁忙,请稍后再试"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new BusinessException("获取锁被中断", e); } } }
|
6.3 案例3:分布式定时任务
6.3.1 场景
需求:定时任务在多个实例中只执行一次。
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Component public class ScheduledTask { @Autowired private RedissonClient redissonClient;
@Scheduled(cron = "0 0 2 * * ?") public void executeTask() { String lockKey = "scheduled:task:lock"; RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(0, 1, TimeUnit.HOURS)) { try { doScheduledTask(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } else { log.info("Task already executed by another instance"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } private void doScheduledTask() { log.info("Executing scheduled task"); } }
|
7. 性能优化
7.1 锁粒度优化
7.1.1 细粒度锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Service public class OrderService {
public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); } }
|
7.2 分段锁
7.2.1 分段锁实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Service public class AccountService {
public void transfer(TransferRequest request) { int segment = (int) (request.getFromAccountId() % 100); String lockKey = "transfer:lock:segment:" + segment; RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, 30, TimeUnit.MILLISECONDS)) { try { doTransfer(request); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
|
7.3 锁超时优化
7.3.1 动态超时时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Service public class OrderService {
public void createOrder(OrderRequest request) { String lockKey = "order:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(100, TimeUnit.MILLISECONDS)) { try { long startTime = System.currentTimeMillis(); doCreateOrder(request); long duration = System.currentTimeMillis() - startTime; long lockTimeout = Math.max(duration * 2, 30000); lock.expire(lockTimeout, TimeUnit.MILLISECONDS); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
|
8. 总结
8.1 核心要点
- 分布式锁实现方式:Redis、ZooKeeper、数据库
- 正确用法:锁在finally中释放、检查锁持有者、设置合理超时时间、使用Watch Dog
- 常见误区:锁未释放、释放其他线程的锁、超时时间不当、未处理获取失败、锁粒度太粗、未考虑锁服务故障
- 性能优化:细粒度锁、分段锁、动态超时时间
- 最佳实践:根据场景选择合适的实现方式,遵循正确的使用模式
8.2 关键理解
- 锁必须在finally中释放:确保锁一定会被释放
- 检查锁的持有者:防止释放其他线程的锁
- 设置合理的超时时间:防止死锁,保证可用性
- 锁粒度要合适:不能太粗,也不能太细
- 考虑锁服务故障:提供降级方案
8.3 最佳实践
- 推荐使用Redisson:功能完善,支持Watch Dog、可重入锁、读写锁
- 锁粒度细化:按业务维度加锁,而不是全局锁
- 使用tryLock:设置超时时间,避免无限等待
- 处理异常:正确处理InterruptedException和锁服务故障
- 性能优化:使用分段锁、动态超时时间等优化手段
相关文章: