基于Redis实现分布式锁
程序员文章站
2022-07-05 13:21:13
...
基于Redis实现分布式锁
第三更,基于Redis实现的分布式锁,参考的是咕泡学院Mic老师的代码,我这里注释写的还是比较清楚了,我使用的是sprinboot,写这篇文章主要是需要的时候自己也可以翻看下。
Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
配置一个Jedis连接池
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisPoolConfiguration {
@Value("${jedis.host}")
private String host;
@Value("${jedis.port}")
private int port;
@Value("${jedis.maxIdle}")
private int maxIdle;
@Value("${jedis.maxTotal}")
private int maxTotal;
@Bean
public JedisPool jedisPool(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMaxTotal(maxTotal);
return new JedisPool(poolConfig,host,port);
}
}
application.properties文件
jedis.host=localhost
jedis.port=6379
jedis.maxIdle=10
jedis.maxTotal=30
Redis 分布式锁
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import java.util.List;
import java.util.UUID;
@Component
public class RedisLock {
private final JedisPool jedisPool;
private static final Logger logger = LoggerFactory.getLogger(RedisLock.class);
@Autowired
public RedisLock(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
/**
* 获得锁
*
* @param key 锁的键
* @param timeout 获得锁的超时时间
* @return 解锁用的唯一标识,超时返回<code>null</code>
*/
public String getLock(String key, int timeout) {
try {
Jedis jedis = jedisPool.getResource();
//定义锁的名称
String lockKey = "redis_lock_" + key;
//解锁用的唯一标识
String value = UUID.randomUUID().toString();
//获得锁的超时时间
long end = System.currentTimeMillis() + timeout;
//在超时时间内去竞争锁
while (System.currentTimeMillis() < end) {
//如果设置成功了就获得了锁,并设置过期时间,返回解锁的唯一标识
if (jedis.setnx(lockKey, value) == 1) {
//设置过期时间,注意这里不是原子操作,可能失败
jedis.expire(lockKey, timeout);
return value;
}
//while循环会执行很快,这里可以根据场景来适当调整或注释掉
Thread.sleep(100);
//如果在设置锁的时候redis挂了,但又没有设置过期时间,在这里就可以设置过期时间
if (jedis.ttl(lockKey) == -1) {
jedis.expire(lockKey, timeout);
}
}
} catch (Exception e) {
logger.error("获得锁异常", e);
}
return null;
}
/**
* 释放锁
*
* @param key 锁的键
* @param value 解锁的唯一标识
* @return
*/
public boolean releaseLock(String key, String value) {
try {
Jedis jedis = jedisPool.getResource();
String lockKey = "redis_lock_" + key;
while (true) {
//监控这个key,如果其他线程将key删除,下面事务中的代码不走
jedis.watch(lockKey);
//如果value和redis中的value一致,删除这个key,否则等待超时
if (value.equals(jedis.get(lockKey))) {
//开启一个事务
Transaction transaction = jedis.multi();
//删除这个key
transaction.del(lockKey);
//执行事务
List<Object> list = transaction.exec();
//如果为空,就继续循环
if (list == null) {
continue;
}
return true;
}
//取消监控
jedis.unwatch();
//如果其他线程将key删除,直接退出循环,返回false
break;
}
} catch (Exception e) {
logger.error("释放锁异常", e);
}
return false;
}
}
上一篇: 检索当前线程的堆栈信息
下一篇: Win32:其他API