Spring Boot + RedisTemplate实现
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeUnit; public class RedisTemplateDistributedLock { private StringRedisTemplate redisTemplate; private String lockKey; private String lockValue; private int expireTime; // 毫秒 public RedisTemplateDistributedLock(StringRedisTemplate redisTemplate, String lockKey, int expireTime) { this.redisTemplate = redisTemplate; this.lockKey = lockKey; this.expireTime = expireTime; this.lockValue = UUID.randomUUID().toString(); } public boolean tryLock(long waitTime) throws InterruptedException { long start = System.currentTimeMillis(); while (true) { Boolean acquired = redisTemplate.opsForValue().setIfAbsent( lockKey, lockValue, expireTime, TimeUnit.MILLISECONDS); if (Boolean.TRUE.equals(acquired)) { return true; } if (System.currentTimeMillis() - start >= waitTime) { return false; } Thread.sleep(100); } } public void unlock() { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + "return redis.call('del', KEYS[1]) " + "else " + "return 0 " + "end"; redisTemplate.execute( new DefaultRedisScript<>(script, Long.class), Collections.singletonList(lockKey), lockValue ); } }
分布式锁的最佳实践
-
设置合理的过期时间:确保锁能够自动释放,防止死锁
-
使用唯一标识:确保只有锁的持有者才能释放锁
-
避免长时间持有锁:锁的持有时间应尽可能短
-
考虑锁的可重入性:如果需要可重入锁,可以使用Redisson的实现
-
处理锁续期问题:对于长时间任务,考虑实现锁的自动续期机制
注意事项
-
Redis分布式锁在集群环境下可能存在脑裂问题,可以考虑使用RedLock算法
-
锁的获取和释放必须是原子操作,使用Lua脚本可以保证这一点
-
网络延迟和Redis故障需要考虑,分布式锁并不是100%可靠的