如何用Spring Boot实现分布式锁?

我来详细讲解Spring Boot中实现分布式锁的几种方式,包括手写Redis锁和使用Redisson框架。

一、基于Redis原生命令实现分布式锁

1. 基础版Redis分布式锁

java 复制代码
@Component
public class RedisDistributedLock {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String LOCK_PREFIX = "distributed:lock:";
    private static final long DEFAULT_EXPIRE_TIME = 30000; // 30秒
    private static final long DEFAULT_WAIT_TIME = 10000;   // 10秒
    private static final long DEFAULT_SLEEP_TIME = 100;    // 100ms
    
    /**
     * 尝试获取分布式锁(简单版)
     * @param lockKey 锁的key
     * @param value 锁的值(通常用UUID)
     * @param expireTime 锁的过期时间(ms)
     * @return 是否获取成功
     */
    public boolean tryLock(String lockKey, String value, long expireTime) {
        String key = LOCK_PREFIX + lockKey;
        
        // 使用SET命令,通过NX参数实现"不存在时设置",EX参数设置过期时间
        Boolean result = redisTemplate.opsForValue()
            .setIfAbsent(key, value, expireTime, TimeUnit.MILLISECONDS);
        
        return Boolean.TRUE.equals(result);
    }
    
    /**
     * 释放锁
     * 需要确保是自己加的锁才能释放(防止释放别人的锁)
     */
    public boolean releaseLock(String lockKey, String value) {
        String key = LOCK_PREFIX + lockKey;
        String currentValue = redisTemplate.opsForValue().get(key);
        
        // 通过Lua脚本确保原子性:判断值是否匹配,匹配则删除
        String luaScript = 
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
            "   return redis.call('del', KEYS[1]) " +
            "else " +
            "   return 0 " +
            "end";
        
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(luaScript);
        redisScript.setResultType(Long.class);
        
        Long result = redisTemplate.execute(
            redisScript, 
            Collections.singletonList(key), 
            value
        );
        
        return result != null && result == 1;
    }
    
    /**
     * 获取锁(支持重试)
     */
    public boolean lockWithRetry(String lockKey, String value, 
                                 long expireTime, long waitTime) {
        long endTime = System.currentTimeMillis() + waitTime;
        
        while (System.currentTimeMillis() < endTime) {
            if (tryLock(lockKey, value, expireTime)) {
                return true;
            }
            
            try {
                Thread.sleep(DEFAULT_SLEEP_TIME);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        
        return false;
    }
}

2. 可重入锁实现

vbnet 复制代码
@Component
public class RedisReentrantLock {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String LOCK_PREFIX = "reentrant:lock:";
    private static final ThreadLocal<Map<String, Integer>> LOCK_COUNT = 
        ThreadLocal.withInitial(HashMap::new);
    
    /**
     * 可重入锁实现
     */
    public boolean tryReentrantLock(String lockKey, String clientId, 
                                    long expireTime) {
        String key = LOCK_PREFIX + lockKey;
        
        Map<String, Integer> lockCountMap = LOCK_COUNT.get();
        int count = lockCountMap.getOrDefault(lockKey, 0);
        
        // 重入:当前线程已持有锁
        if (count > 0) {
            lockCountMap.put(lockKey, count + 1);
            return true;
        }
        
        // 尝试获取锁
        String luaScript = 
            "if redis.call('exists', KEYS[1]) == 0 then " +
            "   redis.call('hset', KEYS[1], 'owner', ARGV[1]) " +
            "   redis.call('hset', KEYS[1], 'count', 1) " +
            "   redis.call('pexpire', KEYS[1], ARGV[2]) " +
            "   return 1 " +
            "elseif redis.call('hget', KEYS[1], 'owner') == ARGV[1] then " +
            "   local count = redis.call('hget', KEYS[1], 'count') " +
            "   redis.call('hset', KEYS[1], 'count', tonumber(count) + 1) " +
            "   redis.call('pexpire', KEYS[1], ARGV[2]) " +
            "   return 1 " +
            "else " +
            "   return 0 " +
            "end";
        
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(luaScript);
        script.setResultType(Long.class);
        
        Long result = redisTemplate.execute(
            script,
            Collections.singletonList(key),
            clientId,
            String.valueOf(expireTime)
        );
        
        if (result != null && result == 1) {
            lockCountMap.put(lockKey, 1);
            return true;
        }
        
        return false;
    }
    
    /**
     * 释放可重入锁
     */
    public boolean releaseReentrantLock(String lockKey, String clientId) {
        String key = LOCK_PREFIX + lockKey;
        
        Map<String, Integer> lockCountMap = LOCK_COUNT.get();
        int count = lockCountMap.getOrDefault(lockKey, 0);
        
        if (count <= 0) {
            return false;
        }
        
        if (count > 1) {
            // 重入次数减1
            lockCountMap.put(lockKey, count - 1);
            return true;
        }
        
        // 最后一次重入,释放锁
        String luaScript = 
            "if redis.call('hget', KEYS[1], 'owner') == ARGV[1] then " +
            "   local current = redis.call('hget', KEYS[1], 'count') " +
            "   if tonumber(current) > 1 then " +
            "       redis.call('hset', KEYS[1], 'count', tonumber(current) - 1) " +
            "       redis.call('pexpire', KEYS[1], ARGV[2]) " +
            "       return 0 " +
            "   else " +
            "       redis.call('del', KEYS[1]) " +
            "       return 1 " +
            "   end " +
            "else " +
            "   return -1 " +
            "end";
        
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(luaScript);
        script.setResultType(Long.class);
        
        Long result = redisTemplate.execute(
            script,
            Collections.singletonList(key),
            clientId,
            "30000"
        );
        
        if (result != null && result == 1) {
            lockCountMap.remove(lockKey);
            if (lockCountMap.isEmpty()) {
                LOCK_COUNT.remove();
            }
            return true;
        }
        
        return false;
    }
}

二、使用Redisson实现分布式锁(推荐生产环境使用)

1. 添加依赖

xml 复制代码
<!-- pom.xml -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.5</version>
</dependency>

2. 配置Redisson

yaml 复制代码
# application.yml
spring:
  redis:
    host: localhost
    port: 6379
    database: 0
    timeout: 3000

redisson:
  config: |
    singleServerConfig:
      address: "redis://${spring.redis.host}:${spring.redis.port}"
      database: ${spring.redis.database}
      connectionPoolSize: 64
      connectionMinimumIdleSize: 24
      idleConnectionTimeout: 10000
      connectTimeout: ${spring.redis.timeout}
      timeout: ${spring.redis.timeout}
      retryAttempts: 3
      retryInterval: 1500

3. Redisson分布式锁服务

java 复制代码
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedissonDistributedLock {
    
    @Autowired
    private RedissonClient redissonClient;
    
    /**
     * 可重入锁(最常用)
     */
    public boolean tryReentrantLock(String lockKey, long waitTime, 
                                    long leaseTime, TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
    
    /**
     * 公平锁
     */
    public boolean tryFairLock(String lockKey, long waitTime, 
                               long leaseTime, TimeUnit unit) {
        RLock lock = redissonClient.getFairLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
    
    /**
     * 联锁(多个锁同时获取)
     */
    public boolean tryMultiLock(String[] lockKeys, long waitTime, 
                                long leaseTime, TimeUnit unit) {
        RLock[] locks = new RLock[lockKeys.length];
        for (int i = 0; i < lockKeys.length; i++) {
            locks[i] = redissonClient.getLock(lockKeys[i]);
        }
        
        RLock multiLock = redissonClient.getMultiLock(locks);
        try {
            return multiLock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
    
    /**
     * 红锁(RedLock,多个Redis实例)
     */
    public boolean tryRedLock(String lockKey, long waitTime, 
                              long leaseTime, TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
    
    /**
     * 释放锁
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
    
    /**
     * 强制释放锁
     */
    public void forceUnlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.forceUnlock();
    }
    
    /**
     * 自动续期的锁(看门狗机制)
     */
    public void lockWithWatchdog(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(); // 默认30秒,看门狗会自动续期
    }
}

4. 使用AOP简化分布式锁使用

less 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DistributedLock {
    
    /** 锁的key,支持SpEL表达式 */
    String key();
    
    /** 锁类型,默认可重入锁 */
    LockType lockType() default LockType.REENTRANT;
    
    /** 等待时间(秒) */
    long waitTime() default 5;
    
    /** 持有时间(秒),-1表示使用看门狗自动续期 */
    long leaseTime() default -1;
    
    /** 时间单位 */
    TimeUnit timeUnit() default TimeUnit.SECONDS;
    
    enum LockType {
        REENTRANT,      // 可重入锁
        FAIR,           // 公平锁
        READ,           // 读锁
        WRITE,          // 写锁
        MULTI,          // 联锁
        RED             // 红锁
    }
}
scss 复制代码
@Aspect
@Component
@Slf4j
public class DistributedLockAspect {
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Autowired
    private RedissonDistributedLock redissonDistributedLock;
    
    @Around("@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, 
                         DistributedLock distributedLock) throws Throwable {
        String lockKey = parseKey(distributedLock.key(), joinPoint);
        RLock lock = getLock(lockKey, distributedLock.lockType());
        
        boolean locked = false;
        try {
            // 尝试获取锁
            if (distributedLock.leaseTime() == -1) {
                // 使用看门狗自动续期
                lock.lock();
            } else {
                locked = lock.tryLock(
                    distributedLock.waitTime(),
                    distributedLock.leaseTime(),
                    distributedLock.timeUnit()
                );
            }
            
            if (!locked && distributedLock.leaseTime() != -1) {
                throw new RuntimeException("获取分布式锁失败: " + lockKey);
            }
            
            log.info("获取分布式锁成功: {}", lockKey);
            return joinPoint.proceed();
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取分布式锁被中断", e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("释放分布式锁: {}", lockKey);
            }
        }
    }
    
    private String parseKey(String keySpEL, ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        // 解析SpEL表达式
        if (keySpEL.startsWith("#")) {
            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(keySpEL);
            
            EvaluationContext context = new StandardEvaluationContext();
            context.setVariable("methodName", method.getName());
            
            // 设置参数
            Object[] args = joinPoint.getArgs();
            Parameter[] parameters = method.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                context.setVariable(parameters[i].getName(), args[i]);
            }
            
            return expression.getValue(context, String.class);
        }
        
        return keySpEL;
    }
    
    private RLock getLock(String lockKey, DistributedLock.LockType lockType) {
        switch (lockType) {
            case FAIR:
                return redissonClient.getFairLock(lockKey);
            case READ:
                return redissonClient.getReadWriteLock(lockKey).readLock();
            case WRITE:
                return redissonClient.getReadWriteLock(lockKey).writeLock();
            case MULTI:
            case RED:
                // 简化处理,实际使用需要多个实例
                return redissonClient.getLock(lockKey);
            case REENTRANT:
            default:
                return redissonClient.getLock(lockKey);
        }
    }
}

三、使用Spring Integration实现分布式锁

1. 添加依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-redis</artifactId>
</dependency>

2. 配置Redis锁注册表

typescript 复制代码
@Configuration
public class RedisLockConfiguration {
    
    @Bean
    public RedisLockRegistry redisLockRegistry(RedisConnectionFactory connectionFactory) {
        // 过期时间10秒
        return new RedisLockRegistry(connectionFactory, "distributed-lock", 10000L);
    }
    
    @Bean
    public LockRegistry lockRegistry(RedisLockRegistry redisLockRegistry) {
        return redisLockRegistry;
    }
}

3. 使用Spring Integration锁

typescript 复制代码
@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private LockRegistry lockRegistry;
    
    public void createOrder(String orderId) {
        Lock lock = lockRegistry.obtain("order:" + orderId);
        
        boolean locked = false;
        try {
            // 尝试获取锁,最多等待5秒
            locked = lock.tryLock(5, TimeUnit.SECONDS);
            
            if (!locked) {
                throw new RuntimeException("系统繁忙,请稍后重试");
            }
            
            // 执行业务逻辑
            processOrder(orderId);
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("订单处理被中断", e);
        } finally {
            if (locked) {
                lock.unlock();
            }
        }
    }
    
    private void processOrder(String orderId) {
        // 订单处理逻辑
        log.info("处理订单: {}", orderId);
    }
}

四、实际应用示例

1. 商品秒杀场景

java 复制代码
@Service
@Slf4j
public class SeckillService {
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private static final String SECKILL_PREFIX = "seckill:product:";
    private static final String LOCK_PREFIX = "seckill:lock:";
    
    /**
     * 秒杀下单(防超卖)
     */
    public boolean seckillOrder(Long productId, Integer quantity, Long userId) {
        String lockKey = LOCK_PREFIX + productId;
        RLock lock = redissonClient.getLock(lockKey);
        
        try {
            // 尝试获取锁,等待100ms,持有锁3秒
            if (!lock.tryLock(100, 3000, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("抢购太火爆,请重试");
            }
            
            // 检查库存
            String stockKey = SECKILL_PREFIX + productId + ":stock";
            Integer stock = Integer.valueOf(
                redisTemplate.opsForValue().get(stockKey)
            );
            
            if (stock == null || stock < quantity) {
                throw new RuntimeException("库存不足");
            }
            
            // 扣减库存
            Long newStock = redisTemplate.opsForValue().decrement(stockKey, quantity);
            if (newStock < 0) {
                // 库存不足,恢复库存
                redisTemplate.opsForValue().increment(stockKey, quantity);
                throw new RuntimeException("库存不足");
            }
            
            // 创建订单
            createOrder(productId, quantity, userId);
            
            return true;
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("系统异常", e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    
    /**
     * 使用注解简化版
     */
    @DistributedLock(
        key = "'seckill:lock:' + #productId",
        waitTime = 1,
        leaseTime = 3,
        timeUnit = TimeUnit.SECONDS
    )
    public boolean seckillOrderWithAnnotation(Long productId, Integer quantity, Long userId) {
        // 业务逻辑,无需关心锁的获取和释放
        String stockKey = SECKILL_PREFIX + productId + ":stock";
        Integer stock = Integer.valueOf(
            redisTemplate.opsForValue().get(stockKey)
        );
        
        if (stock == null || stock < quantity) {
            throw new RuntimeException("库存不足");
        }
        
        Long newStock = redisTemplate.opsForValue().decrement(stockKey, quantity);
        if (newStock < 0) {
            redisTemplate.opsForValue().increment(stockKey, quantity);
            throw new RuntimeException("库存不足");
        }
        
        createOrder(productId, quantity, userId);
        return true;
    }
    
    private void createOrder(Long productId, Integer quantity, Long userId) {
        // 创建订单逻辑
        log.info("用户{}抢购商品{},数量{}", userId, productId, quantity);
    }
}

2. 定时任务防重复执行

typescript 复制代码
@Component
@Slf4j
public class ScheduledTasks {
    
    @Autowired
    private RedissonClient redissonClient;
    
    /**
     * 分布式定时任务,确保集群中只有一个实例执行
     */
    @Scheduled(cron = "0 */5 * * * ?") // 每5分钟执行一次
    public void syncDataTask() {
        String lockKey = "task:sync:data";
        RLock lock = redissonClient.getLock(lockKey);
        
        // 不等待,获取不到锁直接返回
        boolean locked = lock.tryLock();
        if (!locked) {
            log.info("其他节点正在执行数据同步任务");
            return;
        }
        
        try {
            log.info("开始执行数据同步任务");
            // 执行业务逻辑
            syncData();
            log.info("数据同步任务完成");
        } finally {
            lock.unlock();
        }
    }
    
    private void syncData() {
        // 数据同步逻辑
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

五、配置和最佳实践

1. Redisson配置类

scss 复制代码
@Configuration
public class RedissonConfig {
    
    @Value("${spring.redis.host}")
    private String redisHost;
    
    @Value("${spring.redis.port}")
    private String redisPort;
    
    @Value("${spring.redis.password:}")
    private String password;
    
    @Value("${spring.redis.database:0}")
    private int database;
    
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() {
        Config config = new Config();
        
        // 单节点模式
        config.useSingleServer()
            .setAddress(String.format("redis://%s:%s", redisHost, redisPort))
            .setDatabase(database)
            .setPassword(StringUtils.hasText(password) ? password : null)
            .setConnectionPoolSize(64)
            .setConnectionMinimumIdleSize(10)
            .setIdleConnectionTimeout(10000)
            .setConnectTimeout(3000)
            .setTimeout(3000)
            .setRetryAttempts(3)
            .setRetryInterval(1500)
            .setPingConnectionInterval(30000)
            .setKeepAlive(true);
        
        // 锁配置
        config.setLockWatchdogTimeout(30000L); // 看门狗超时时间
        
        return Redisson.create(config);
    }
}

2. 分布式锁工具类

csharp 复制代码
@Component
@Slf4j
public class DistributedLockUtil {
    
    @Autowired
    private RedissonClient redissonClient;
    
    /**
     * 执行带锁的方法
     */
    public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime, 
                                  TimeUnit unit, Supplier<T> supplier) {
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;
        
        try {
            locked = lock.tryLock(waitTime, leaseTime, unit);
            if (!locked) {
                throw new DistributedLockException("获取分布式锁失败: " + lockKey);
            }
            
            return supplier.get();
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new DistributedLockException("获取分布式锁被中断", e);
        } finally {
            if (locked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    
    /**
     * 执行带锁的方法(无返回值)
     */
    public void executeWithLock(String lockKey, long waitTime, long leaseTime,
                               TimeUnit unit, Runnable runnable) {
        executeWithLock(lockKey, waitTime, leaseTime, unit, () -> {
            runnable.run();
            return null;
        });
    }
    
    /**
     * 执行带锁的方法(快速失败)
     */
    public <T> Optional<T> tryExecuteWithLock(String lockKey, long waitTime, 
                                             long leaseTime, TimeUnit unit,
                                             Supplier<T> supplier) {
        try {
            return Optional.ofNullable(
                executeWithLock(lockKey, waitTime, leaseTime, unit, supplier)
            );
        } catch (DistributedLockException e) {
            log.warn("获取锁失败,跳过执行: {}", lockKey);
            return Optional.empty();
        }
    }
    
    public static class DistributedLockException extends RuntimeException {
        public DistributedLockException(String message) {
            super(message);
        }
        
        public DistributedLockException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}

六、测试分布式锁

ini 复制代码
@SpringBootTest
@Slf4j
class DistributedLockTest {
    
    @Autowired
    private RedissonDistributedLock redissonDistributedLock;
    
    @Autowired
    private DistributedLockUtil distributedLockUtil;
    
    private final AtomicInteger counter = new AtomicInteger(0);
    
    @Test
    void testConcurrentLock() throws InterruptedException {
        int threadCount = 10;
        String lockKey = "test:concurrent:lock";
        CountDownLatch latch = new CountDownLatch(threadCount);
        
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        
        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                try {
                    boolean locked = redissonDistributedLock
                        .tryReentrantLock(lockKey, 2, 5, TimeUnit.SECONDS);
                    
                    if (locked) {
                        try {
                            // 模拟业务处理
                            Thread.sleep(100);
                            int value = counter.incrementAndGet();
                            log.info("线程 {} 获取锁成功,计数: {}", 
                                    Thread.currentThread().getName(), value);
                        } finally {
                            redissonDistributedLock.unlock(lockKey);
                        }
                    } else {
                        log.warn("线程 {} 获取锁失败", Thread.currentThread().getName());
                    }
                } catch (Exception e) {
                    log.error("线程执行异常", e);
                } finally {
                    latch.countDown();
                }
            });
        }
        
        latch.await();
        executor.shutdown();
        
        assertEquals(threadCount, counter.get());
    }
    
    @Test
    void testLockWithUtil() {
        String lockKey = "test:util:lock";
        
        String result = distributedLockUtil.executeWithLock(
            lockKey, 
            2, 
            5, 
            TimeUnit.SECONDS,
            () -> {
                // 业务逻辑
                return "success";
            }
        );
        
        assertEquals("success", result);
    }
}

总结与建议

1. 选择方案

  • 简单场景 :使用Spring Integration的RedisLockRegistry
  • 生产环境 :推荐使用Redisson,功能最全,稳定性最好
  • 特殊需求:需要精细控制时,可以使用原生Redis命令自定义

2. 最佳实践

  • 锁的key要有业务含义,如order:create:{orderId}
  • 一定要设置合理的过期时间,防止死锁
  • 释放锁时要检查是否当前线程持有
  • 使用Lua脚本保证原子性
  • 考虑锁的可重入性
  • 生产环境使用Redis集群或哨兵模式

3. 注意事项

  • 避免锁粒度过大,影响并发性能
  • 避免锁持有时间过长
  • 实现锁的自动续期(看门狗机制)
  • 考虑锁等待超时和快速失败
  • 添加监控和告警机制

4. 常见问题解决

  • 锁提前过期:使用Redisson的看门狗机制
  • 锁误删:每个锁设置唯一value,释放时验证
  • 锁不可重入:使用Redisson或实现可重入逻辑
  • Redis集群故障:使用RedLock算法(多个Redis实例)

这样实现的分布式锁既安全又可靠,可以满足大多数业务场景的需求。

相关推荐
無限進步D3 小时前
Java 运行原理
java·开发语言·入门
難釋懷3 小时前
安装Canal
java
是苏浙3 小时前
JDK17新增特性
java·开发语言
不光头强3 小时前
spring cloud知识总结
后端·spring·spring cloud
SPC的存折4 小时前
1、Redis数据库基础
linux·运维·服务器·数据库·redis·缓存
GetcharZp6 小时前
告别 Python 依赖!用 LangChainGo 打造高性能大模型应用,Go 程序员必看!
后端
阿里加多6 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood6 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员7 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai