并发锁和分布式锁是解决并发问题的两种重要机制,它们既有区别又有联系。
一、核心区别对比
| 维度 |
并发锁(本地锁) |
分布式锁 |
| 作用范围 |
单进程内,多线程之间 |
跨进程、跨服务、跨机器 |
| 应用场景 |
单机应用,多线程并发 |
分布式系统,多服务实例 |
| 实现原理 |
基于JVM内存或操作系统机制 |
基于外部中间件协调 |
| 性能影响 |
性能开销小,速度快 |
性能开销大,网络延迟 |
| 复杂度 |
实现简单,API丰富 |
实现复杂,需要考虑网络分区、脑裂等问题 |
二、技术实现对比
并发锁的实现方式
1. synchronized关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class SynchronizedExample { private int counter = 0; private final Object lock = new Object(); public synchronized void increment() { counter++; } public void incrementWithBlock() { synchronized(lock) { counter++; } } }
|
2. ReentrantLock可重入锁
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
| public class ReentrantLockExample { private final ReentrantLock lock = new ReentrantLock(); private int counter = 0; public void increment() { lock.lock(); try { counter++; } finally { lock.unlock(); } } public boolean tryIncrement() { if (lock.tryLock(1, TimeUnit.SECONDS)) { try { counter++; return true; } finally { lock.unlock(); } } return false; } }
|
3. ReadWriteLock读写锁
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
| public class ReadWriteLockExample { private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); private final Lock readLock = rwLock.readLock(); private final Lock writeLock = rwLock.writeLock(); private Map<String, String> data = new HashMap<>(); public String get(String key) { readLock.lock(); try { return data.get(key); } finally { readLock.unlock(); } } public void put(String key, String value) { writeLock.lock(); try { data.put(key, value); } finally { writeLock.unlock(); } } }
|
分布式锁的实现方式
1. Redis分布式锁
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
| public class RedisDistributedLock { private JedisPool jedisPool; public boolean lock(String lockKey, String clientId, long expireSeconds) { try (Jedis jedis = jedisPool.getResource()) { String result = jedis.set(lockKey, clientId, SetParams.setParams().nx().ex(expireSeconds)); return "OK".equals(result); } } public boolean unlock(String lockKey, String clientId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + " return redis.call('del', KEYS[1]) " + "else " + " return 0 " + "end"; try (Jedis jedis = jedisPool.getResource()) { Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(clientId)); return Long.valueOf(1L).equals(result); } } }
|
2. Redisson分布式锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class RedissonLockExample { private RedissonClient redisson; public void processWithLock(String lockKey) { RLock lock = redisson.getLock(lockKey); try { boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS); if (locked) { doBusiness(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
|
三、联系与协同工作
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
| public class OrderService { private final ReentrantLock localLock = new ReentrantLock(); @Autowired private DistributedLock distributedLock; public void createOrder(Order order) { localLock.lock(); try { String lockKey = "order_create:" + order.getUserId(); if (distributedLock.tryLock(lockKey, 5, TimeUnit.SECONDS)) { try { doCreateOrder(order); } finally { distributedLock.unlock(lockKey); } } else { throw new RuntimeException("订单创建过于频繁"); } } finally { localLock.unlock(); } } }
|
2. 设计模式结合
双重检查锁定模式(DCL)在分布式环境的应用
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
| public class DistributedSingleton { private volatile Object cachedData; private final Object localLock = new Object(); public Object getData() { if (cachedData == null) { synchronized (localLock) { if (cachedData == null) { String lockKey = "data_init_lock"; if (distributedLock.tryLock(lockKey, 10, TimeUnit.SECONDS)) { try { if (cachedData == null) { cachedData = loadDataFromDB(); } } finally { distributedLock.unlock(lockKey); } } } } } return cachedData; } }
|
四、适用场景对比
适合使用并发锁的场景
场景1:单机内存计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class LocalCounter { private final AtomicLong counter = new AtomicLong(0); private final ReentrantLock calculationLock = new ReentrantLock(); public void complexCalculation() { calculationLock.lock(); try { long result = performComplexMath(counter.get()); counter.set(result); } finally { calculationLock.unlock(); } } }
|
场景2:线程安全的集合操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ThreadSafeCollection { private final List<String> data = new ArrayList<>(); private final ReentrantLock listLock = new ReentrantLock(); public void batchAdd(List<String> newItems) { listLock.lock(); try { data.addAll(newItems); Collections.sort(data); } finally { listLock.unlock(); } } }
|
适合使用分布式锁的场景
场景1:分布式定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class DistributedScheduler { @Scheduled(cron = "0 0/5 * * * ?") public void distributedTask() { String lockKey = "scheduled_task:data_sync"; if (distributedLock.tryLock(lockKey, 4, TimeUnit.MINUTES)) { try { executeDataSync(); } finally { distributedLock.unlock(lockKey); } } } }
|
场景2:全局资源访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class GlobalResourceManager { public boolean allocateResource(String resourceId, String clientId) { String lockKey = "resource_allocation:" + resourceId; if (distributedLock.tryLock(lockKey, 10, TimeUnit.SECONDS)) { try { Resource resource = resourceDao.findById(resourceId); if (resource.getStatus() == Status.AVAILABLE) { resource.setStatus(Status.ALLOCATED); resource.setOwner(clientId); resourceDao.update(resource); return true; } return false; } finally { distributedLock.unlock(lockKey); } } throw new RuntimeException("资源分配失败,请重试"); } }
|
五、混合使用的最佳实践
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
| public class CachedService { private final ConcurrentHashMap<String, Object> localCache = new ConcurrentHashMap<>(); private final ReadWriteLock cacheLock = new ReentrantReadWriteLock(); public Object getWithDistributedLock(String key) { cacheLock.readLock().lock(); try { Object value = localCache.get(key); if (value != null) { return value; } } finally { cacheLock.readLock().unlock(); } String distributedLockKey = "cache_load:" + key; if (distributedLock.tryLock(distributedLockKey, 5, TimeUnit.SECONDS)) { try { cacheLock.readLock().lock(); try { Object value = localCache.get(key); if (value != null) { return value; } } finally { cacheLock.readLock().unlock(); } Object loadedValue = loadFromDataSource(key); cacheLock.writeLock().lock(); try { localCache.put(key, loadedValue); } finally { cacheLock.writeLock().unlock(); } return loadedValue; } finally { distributedLock.unlock(distributedLockKey); } } throw new RuntimeException("系统繁忙,请重试"); } }
|
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
| public class OptimizedLockManager { private final RateLimiter localRateLimiter = RateLimiter.create(1000); private final ReentrantLock localTryLock = new ReentrantLock(); public boolean tryAcquireWithOptimization(String resourceKey) { if (!localRateLimiter.tryAcquire()) { return false; } if (!localTryLock.tryLock()) { return false; } try { return distributedLock.tryLock(resourceKey, 1, TimeUnit.SECONDS); } finally { localTryLock.unlock(); } } }
|
六、总结
核心联系
- 共同目标:都是解决并发访问共享资源的问题
- 互补关系:在分布式系统中往往需要结合使用
- 设计思想:都基于互斥、可见性、有序性等并发原理
选择原则
- 单机应用:优先使用并发锁,性能更好
- 分布式系统:必须使用分布式锁保证跨进程一致性
- 混合场景:使用并发锁做本地优化,分布式锁做全局保证
- 性能敏感:尽量减少分布式锁的使用范围和时间
理解两者的区别和联系,有助于在合适的场景选择合适的技术方案,构建高性能、高可用的并发系统。
并发锁和分布式锁有各自明确的应用场景,选择正确的锁类型对系统性能和可靠性至关重要。
一、并发锁(本地锁)应用场景
1. 单机内存数据保护
场景:线程安全的计数器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class LocalCounterService { private final ReentrantLock counterLock = new ReentrantLock(); private final Map<String, AtomicInteger> counters = new HashMap<>(); public void increment(String counterName) { counterLock.lock(); try { counters.computeIfAbsent(counterName, k -> new AtomicInteger(0)) .incrementAndGet(); } finally { counterLock.unlock(); } } }
|
场景:缓存更新操作
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
| public class LocalCacheManager { private final ReadWriteLock cacheLock = new ReentrantReadWriteLock(); private final Map<String, Object> cache = new ConcurrentHashMap<>(); public void refreshCache() { cacheLock.writeLock().lock(); try { cache.clear(); cache.putAll(loadDataFromDB()); } finally { cacheLock.writeLock().unlock(); } } public Object getFromCache(String key) { cacheLock.readLock().lock(); try { return cache.get(key); } finally { cacheLock.readLock().unlock(); } } }
|
2. 复杂业务逻辑原子性
场景:订单状态流转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class OrderStateMachine { private final Object orderLock = new Object(); public boolean transitionOrderState(Long orderId, OrderState from, OrderState to) { synchronized (orderLock) { Order order = orderDAO.findById(orderId); if (order.getState() != from) { return false; } if (validateTransition(order, from, to)) { order.setState(to); orderDAO.update(order); return true; } return false; } } }
|
3. 资源池管理
场景:数据库连接池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class SimpleConnectionPool { private final ReentrantLock poolLock = new ReentrantLock(); private final List<Connection> idleConnections = new ArrayList<>(); private final Set<Connection> activeConnections = new HashSet<>(); public Connection getConnection() throws SQLException { poolLock.lock(); try { if (!idleConnections.isEmpty()) { Connection conn = idleConnections.remove(0); activeConnections.add(conn); return conn; } Connection newConn = createNewConnection(); activeConnections.add(newConn); return newConn; } finally { poolLock.unlock(); } } }
|
4. 批量操作原子性
场景:批量数据处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class BatchDataProcessor { private final ReentrantLock batchLock = new ReentrantLock(); private List<Data> batchData = new ArrayList<>(); public void addToBatch(Data data) { batchLock.lock(); try { batchData.add(data); if (batchData.size() >= BATCH_SIZE) { processBatch(batchData); batchData.clear(); } } finally { batchLock.unlock(); } } }
|
二、分布式锁应用场景
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
| @Service public class DistributedInventoryService { @Autowired private DistributedLock distributedLock; public boolean deductStock(Long productId, Integer quantity) { String lockKey = "stock_deduction:" + productId; if (!distributedLock.tryLock(lockKey, 3, TimeUnit.SECONDS)) { throw new BusinessException("系统繁忙,请重试"); } try { Product product = productDAO.selectById(productId); if (product.getStock() >= quantity) { product.setStock(product.getStock() - quantity); productDAO.updateById(product); inventoryLogService.logDeduction(productId, quantity); return true; } return false; } finally { distributedLock.unlock(lockKey); } } }
|
2. 分布式定时任务
场景:集群任务调度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Component public class DistributedScheduler { @Autowired private DistributedLock distributedLock; @Scheduled(fixedRate = 60000) public void dataSyncTask() { String lockKey = "task:data_sync"; if (distributedLock.tryLock(lockKey, 55, TimeUnit.SECONDS)) { try { log.info("开始执行数据同步任务"); dataSyncService.syncAllData(); log.info("数据同步任务完成"); } finally { distributedLock.unlock(lockKey); } } } }
|
3. 分布式唯一性控制
场景:防重复提交
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
| @RestController public class OrderController { @Autowired private DistributedLock distributedLock; @PostMapping("/order/create") public ResponseEntity createOrder(@RequestBody OrderRequest request) { String requestId = request.getRequestId(); String lockKey = "order_create:" + requestId; if (!distributedLock.tryLock(lockKey, 30, TimeUnit.SECONDS)) { throw new BusinessException("请勿重复提交订单"); } try { if (orderService.isRequestProcessed(requestId)) { return ResponseEntity.ok("订单已创建"); } Order order = orderService.createOrder(request); return ResponseEntity.ok(order); } finally { distributedLock.unlock(lockKey); } } }
|
4. 全局配置更新
场景:分布式配置管理
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
| @Service public class GlobalConfigService { @Autowired private DistributedLock distributedLock; public void updateGlobalConfig(Config newConfig) { String lockKey = "global_config_update"; if (!distributedLock.tryLock(lockKey, 10, TimeUnit.SECONDS)) { throw new BusinessException("配置更新中,请稍后重试"); } try { configDAO.update(newConfig); cacheEvictionService.evictAllNodes("config_cache"); eventPublisher.publishConfigChangeEvent(newConfig); } finally { distributedLock.unlock(lockKey); } } }
|
5. 分布式序列生成
场景:全局唯一ID生成
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
| @Service public class DistributedIdGenerator { @Autowired private DistributedLock distributedLock; @Autowired private RedisTemplate redisTemplate; public Long generateOrderId() { String lockKey = "id_generator:order"; String counterKey = "order_id_counter"; if (!distributedLock.tryLock(lockKey, 2, TimeUnit.SECONDS)) { throw new BusinessException("ID生成服务繁忙"); } try { Long nextId = redisTemplate.opsForValue().increment(counterKey); return nextId; } finally { distributedLock.unlock(lockKey); } } }
|
三、混合使用场景
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
| @Service public class MultiLevelCacheService { private final ReentrantLock localCacheLock = new ReentrantLock(); private final Map<String, Object> localCache = new HashMap<>(); @Autowired private DistributedLock distributedLock; public Object getData(String key) { Object localValue = localCache.get(key); if (localValue != null) { return localValue; } localCacheLock.lock(); try { localValue = localCache.get(key); if (localValue != null) { return localValue; } String distributedLockKey = "cache_loading:" + key; if (distributedLock.tryLock(distributedLockKey, 5, TimeUnit.SECONDS)) { try { Object data = loadFromDataSource(key); localCache.put(key, data); return data; } finally { distributedLock.unlock(distributedLockKey); } } throw new BusinessException("数据加载中,请重试"); } finally { localCacheLock.unlock(); } } }
|
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
| @Service public class DistributedBatchProcessor { private final ReentrantLock batchLock = new ReentrantLock(); private final Map<String, List<Data>> batches = new HashMap<>(); @Autowired private DistributedLock distributedLock; public void addToDistributedBatch(String batchKey, Data data) { batchLock.lock(); try { batches.computeIfAbsent(batchKey, k -> new ArrayList<>()) .add(data); List<Data> currentBatch = batches.get(batchKey); if (currentBatch.size() >= BATCH_SIZE) { String distributedLockKey = "batch_process:" + batchKey; if (distributedLock.tryLock(distributedLockKey, 10, TimeUnit.SECONDS)) { try { processBatch(batchKey, currentBatch); batches.remove(batchKey); } finally { distributedLock.unlock(distributedLockKey); } } } } finally { batchLock.unlock(); } } }
|
四、选择原则总结
使用并发锁当:
- ✅ 单机应用或单服务实例
- ✅ 操作内存数据或本地资源
- ✅ 性能要求极高,需要低延迟
- ✅ 不需要跨进程协调
使用分布式锁当:
- ✅ 分布式系统,多服务实例
- ✅ 操作共享存储(数据库、Redis等)
- ✅ 需要全局唯一性保证
- ✅ 跨进程的资源协调
避免使用锁当:
- ❌ 可以通过无锁数据结构解决
- ❌ 业务允许最终一致性
- ❌ 读多写少且可以使用乐观锁
- ❌ 可以通过消息队列解耦异步处理
正确选择锁类型需要在一致性要求、性能开销和系统复杂度之间做出平衡。