Redis 分布式锁是一种利用 Redis 实现的分布式系统中的锁机制,用于在分布式环境下控制多个客户端对共享资源的访问。它通过 Redis 的原子性操作来确保在分布式系统中的不同节点上,同一时刻只有一个客户端能够获取到锁,从而保证了对共享资源的互斥访问。
分布式锁通常在以下情况下使用:
共享资源访问控制: 当多个客户端需要访问共享资源时,为了避免并发访问导致的数据不一致或竞态条件问题,可以使用分布式锁来控制对资源的访问。防止重复执行: 在分布式系统中,某些操作可能需要保证只能被执行一次,例如定时任务的执行、数据同步等,可以使用分布式锁来确保操作只会被执行一次。避免缓存击穿: 当缓存中的数据过期时,可能会出现大量并发请求同时访问数据库的情况,为了避免这种情况,可以使用分布式锁来保证只有一个请求可以去数据库中重新加载数据,其他请求等待结果返回。
示例代码1:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;import java.util.concurrent.TimeUnit;public class RedissonDistributedLock {private static final String LOCK_KEY = "mylock";private static final long LOCK_EXPIRE_TIME = 30; // 锁的过期时间,单位秒private RedisTemplate<String, String> redisTemplate;private RedissonClient redissonClient;public RedissonDistributedLock(RedisTemplate<String, String> redisTemplate, RedissonClient redissonClient) {this.redisTemplate = redisTemplate;this.redissonClient = redissonClient;}public boolean acquireLock() {RLock lock = redissonClient.getLock(LOCK_KEY);try {return lock.tryLock(LOCK_EXPIRE_TIME, TimeUnit.SECONDS);} catch (InterruptedException e) {Thread.currentThread().interrupt();return false;}}public void releaseLock() {RLock lock = redissonClient.getLock(LOCK_KEY);lock.unlock();}public static void main(String[] args) {// 初始化 RedisTemplate 和 RedissonClientRedisTemplate<String, String> redisTemplate = // 初始化 RedisTemplateRedissonClient redissonClient = Redisson.create(); // 初始化 RedissonClientRedissonDistributedLock lock = new RedissonDistributedLock(redisTemplate, redissonClient);try {if (lock.acquireLock()) {// 成功获取锁后执行业务逻辑System.out.println("成功获取到锁,执行业务逻辑...");Thread.sleep(5000); // 模拟业务逻辑执行时间} else {// 获取锁失败,处理逻辑System.out.println("获取锁失败,处理逻辑...");}} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.releaseLock();}}
}
在这个示例中,我们创建了一个 RedissonDistributedLock 类,它接收一个 RedisTemplate 和 RedissonClient 作为参数,并提供了 acquireLock 和 releaseLock 方法来获取和释放锁。在 main 方法中,我们初始化了 RedisTemplate 和 RedissonClient,并使用 RedissonDistributedLock 来实现分布式锁。
示例代码2:
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.util.Collections;public class RedisDistributedLock {private static final String LOCK_KEY = "mylock";private static final String LOCK_VALUE = "locked";private static final long LOCK_EXPIRE_TIME = 30000; // 锁的过期时间,单位毫秒private RedisTemplate<String, String> redisTemplate;public RedisDistributedLock(RedisTemplate<String, String> redisTemplate) {this.redisTemplate = redisTemplate;// 设置 RedisTemplate 的序列化器,保证 key 和 value 都以字符串的形式存储redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new StringRedisSerializer());}public boolean acquireLock() {// 使用 Lua 脚本确保原子性操作String script = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then "+ "redis.call('pexpire', KEYS[1], ARGV[2]) return true else return false end";DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(script, Boolean.class);Boolean result = redisTemplate.execute(redisScript, Collections.singletonList(LOCK_KEY), LOCK_VALUE, String.valueOf(LOCK_EXPIRE_TIME));return result != null && result;}public void releaseLock() {// 释放锁redisTemplate.delete(LOCK_KEY);}public static void main(String[] args) {// 初始化 RedisTemplateRedisConnectionFactory connectionFactory = // 设置 Redis 连接工厂RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(connectionFactory);redisTemplate.afterPropertiesSet();RedisDistributedLock lock = new RedisDistributedLock(redisTemplate);try {if (lock.acquireLock()) {// 成功获取锁后执行业务逻辑System.out.println("成功获取到锁,执行业务逻辑...");Thread.sleep(5000); // 模拟业务逻辑执行时间} else {// 获取锁失败,处理逻辑System.out.println("获取锁失败,处理逻辑...");}} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.releaseLock();}}
}
这段代码使用了 RedisTemplate 来与 Redis 进行交互,通过执行 Lua 脚本来确保获取锁的原子性操作。在 acquireLock 方法中,通过执行 Lua 脚本来设置锁,并设置了锁的过期时间,从而避免了因为程序异常而导致锁永远不释放的情况。在业务逻辑执行完成后,调用 releaseLock 方法来释放锁。