本文目录导读:

我来为您提供几种Java实现分布式锁的完整案例,包括基于Redis和ZooKeeper的实现。
基于Redis的分布式锁
使用Jedis实现(最基础版)
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
import java.util.UUID;
public class RedisDistributedLock {
private static final String LOCK_KEY = "distributed_lock";
private static final long LOCK_EXPIRE_TIME = 30000; // 锁过期时间:30秒
private Jedis jedis;
private String lockValue;
public RedisDistributedLock(Jedis jedis) {
this.jedis = jedis;
}
/**
* 获取分布式锁
*/
public boolean tryLock() {
// 生成唯一标识,用于释放锁时校验
lockValue = UUID.randomUUID().toString();
// 使用SET命令的NX和EX参数实现原子性操作
SetParams params = SetParams.setParams()
.nx() // 不存在时才设置
.ex(30); // 设置过期时间30秒
String result = jedis.set(LOCK_KEY, lockValue, params);
return "OK".equals(result);
}
/**
* 释放分布式锁
*/
public void unlock() {
// 使用Lua脚本保证原子性
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
jedis.eval(script,
java.util.Collections.singletonList(LOCK_KEY),
java.util.Collections.singletonList(lockValue));
}
}
使用Spring Data Redis实现(生产环境推荐)
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Component
public class RedisLockUtil {
@Resource
private RedisTemplate<String, String> redisTemplate;
private static final String LOCK_PREFIX = "redis:lock:";
private static final String UNLOCK_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
/**
* 加锁
* @param lockKey 锁的key
* @param requestId 请求标识(用于防止误删)
* @param expireTime 过期时间
* @return 是否成功
*/
public boolean lock(String lockKey, String requestId, long expireTime) {
try {
String key = LOCK_PREFIX + lockKey;
return Boolean.TRUE.equals(
redisTemplate.opsForValue().setIfAbsent(key, requestId, expireTime, TimeUnit.SECONDS)
);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 解锁
*/
public boolean unlock(String lockKey, String requestId) {
try {
String key = LOCK_PREFIX + lockKey;
// 使用Lua脚本保证原子性
DefaultRedisScript<Long> script = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class);
Long result = redisTemplate.execute(script,
Collections.singletonList(key),
requestId);
return result != null && result > 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
Redisson分布式锁(功能最全)
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import java.util.concurrent.TimeUnit;
public class RedissonDistributedLock {
private RedissonClient redissonClient;
/**
* 初始化Redisson
*/
public void init() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://localhost:6379")
.setPassword("password") // 有密码时配置
.setDatabase(0);
redissonClient = Redisson.create(config);
}
/**
* 使用Redisson实现分布式锁
*/
public void operateWithLock() {
RLock lock = redissonClient.getLock("business-lock");
try {
// 尝试加锁,最多等待10秒,锁自动释放时间为30秒
boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (isLocked) {
try {
// 业务处理
System.out.println("获取锁成功,执行业务逻辑...");
Thread.sleep(5000);
} finally {
// 释放锁(只有持有者才能释放)
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} else {
System.out.println("获取锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
/**
* 使用看门狗机制自动续期
*/
public void operateWithWatchdog() {
RLock lock = redissonClient.getLock("watchdog-lock");
try {
// 默认锁30秒,看门狗每隔10秒自动续期
lock.lock();
try {
// 业务处理(可以长时间运行)
System.out.println("执行业务逻辑,看门狗会自动续期...");
Thread.sleep(60000);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
}
基于ZooKeeper的分布式锁
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class ZookeeperDistributedLock {
private CuratorFramework client;
public ZookeeperDistributedLock() {
// 初始化ZooKeeper客户端
client = CuratorFrameworkFactory.builder()
.connectString("localhost:2181")
.sessionTimeoutMs(5000)
.connectionTimeoutMs(3000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
client.start();
}
/**
* 使用Curator实现分布式锁
*/
public void operateWithLock() {
// 创建分布式锁
InterProcessMutex lock = new InterProcessMutex(client, "/locks/business-lock");
try {
// 获取锁(最多等待10秒)
boolean isLocked = lock.acquire(10, TimeUnit.SECONDS);
if (isLocked) {
try {
// 业务处理
System.out.println("获取ZooKeeper锁成功,执行业务逻辑...");
Thread.sleep(5000);
} finally {
// 释放锁
lock.release();
System.out.println("释放锁成功");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
完整的业务使用案例
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class InventoryService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private RedisLockUtil redisLockUtil;
private static final String INVENTORY_KEY = "inventory:product:1001";
/**
* 扣减库存(使用分布式锁)
*/
public boolean deductStock(String orderId) {
// 生成请求ID
String requestId = orderId + ":" + System.currentTimeMillis();
String lockKey = "product:1001:stock";
// 尝试获取锁
boolean isLocked = redisLockUtil.lock(lockKey, requestId, 30);
if (!isLocked) {
System.out.println("获取分布式锁失败,订单:" + orderId);
return false;
}
try {
// 检查库存
Object stockObj = redisTemplate.opsForValue().get(INVENTORY_KEY);
int stock = stockObj == null ? 0 : Integer.parseInt(stockObj.toString());
if (stock <= 0) {
System.out.println("库存不足,订单:" + orderId);
return false;
}
// 扣减库存
redisTemplate.opsForValue().set(INVENTORY_KEY, String.valueOf(stock - 1));
System.out.println("扣减库存成功,剩余库存:" + (stock - 1) + ",订单:" + orderId);
// 记录订单
saveOrder(orderId, stock - 1);
return true;
} finally {
// 释放锁
redisLockUtil.unlock(lockKey, requestId);
}
}
private void saveOrder(String orderId, int remainingStock) {
// 保存订单到数据库
System.out.println("保存订单:" + orderId + ",剩余库存:" + remainingStock);
}
}
使用Redisson的完整示例
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonLockDemo {
private RedissonClient redissonClient;
public RedissonLockDemo() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://localhost:6379")
.setConnectionPoolSize(10)
.setConnectionMinimumIdleSize(5);
redissonClient = Redisson.create(config);
}
/**
* 分布式锁工具方法
*/
public <T> T executeWithLock(String lockName,
long waitTime,
long leaseTime,
LockCallback<T> callback) {
RLock lock = redissonClient.getLock(lockName);
try {
// 尝试获取锁
boolean isLocked = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
if (!isLocked) {
throw new RuntimeException("获取锁超时,锁名称:" + lockName);
}
try {
// 执行业务逻辑
return callback.execute();
} finally {
// 释放锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("线程被中断", e);
} finally {
// 可选:关闭连接
}
}
@FunctionalInterface
public interface LockCallback<T> {
T execute();
}
// 使用示例
public static void main(String[] args) {
RedissonLockDemo demo = new RedissonLockDemo();
// 执行带锁的业务逻辑
String result = demo.executeWithLock("product-lock", 10, 30, () -> {
System.out.println("执行业务逻辑...");
return "业务执行成功";
});
System.out.println("结果:" + result);
}
}
分布式锁要点总结
核心要点
- 原子性:加锁和解锁操作必须是原子性的
- 唯一定标识:每个锁需要唯一标识,防止误删
- 过期时间:防止死锁
- 锁续期:处理长任务(Redisson看门狗)
选择建议
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Redis SETNX | 简单、性能高 | 可能出现主从切换问题 | 中小型系统 |
| Redisson | 功能完善、自动续期 | 依赖Redisson客户端 | 生产环境推荐 |
| ZooKeeper | 强一致、节点监控 | 性能相对较低 | 对一致性要求高的场景 |
注意事项
- 锁的粒度要合适,避免过大或过小
- 业务执行时间要小于锁的过期时间
- 考虑高可用部署(Redis集群、ZooKeeper集群)
- 做好异常处理和降级方案
有任何具体需求或疑问,欢迎继续探讨!