功能介绍
分布式锁的获取
分布式锁尝试获取
分布式锁的释放
适用范围
需要
支持立即获取锁方式,如果获取到返回true,获取不到则返回false;
支持等待获取锁方式,如果获取到,直接返回true,获取不到在等待一小段时间,在这一小段时间内反复尝试,如果尝试成功,则返回true,等待时间过后还获取不到则返回false;
不能产生死锁的情况;
不能释放非自己加的锁
业务流程图
通过 redis 来实现分布式锁的加锁逻辑如下所示:
image.png
image.png
使用教程
核心代码说明
获取锁
public String lock(String key) {
Jedis jedis = null;
try {
jedis = redisConnection.getJedis();
jedis.select(dbIndex);
key = KEY_PRE + key;
String value = fetchLockValue();
//多个客户端可能拿到同一把锁,用新的redis命令
//redis 在2.6.12版本之后,对 set 命令进行了扩充,能够规避上面的两个问题。新版的 redis set 命令的参数如下SET key value [EX seconds] [PX milliseconds] [NX|XX]
if (SET_SUCCESS.equals(jedis.set(key, value, "NX", "EX", lockExpirseTime))) {
return value;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
return null;
}
解锁
public boolean unLock(String key, String value) {
Long RELEASE_SUCCESS = 1L;
Jedis jedis = null;
try {
jedis = redisConnection.getJedis();
jedis.select(dbIndex);
key = KEY_PRE + key;
//在这里我们利用 redis 执行 Lua 脚本的能力来解决原子操作的问题
String command = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
if (RELEASE_SUCCESS.equals(jedis.eval(command, Collections.singletonList(key), Collections.singletonList(value)))) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}
测试类:RedisLockTest
public class RedisLockTest {
public static void main(String[] args) {
for (int i = 0; i < 9; i++) {
new Thread(new Runnable() {
public void run() {
RedisConnection redisConnection = RedisConnectionUtil.create();
LockServiceRedisImpl lockServiceRedis = new LockServiceRedisImpl();
lockServiceRedis.setRedisConnection(redisConnection);
lockServiceRedis.setDbIndex(15);
lockServiceRedis.setLockExpirseTime(20);
String key = "20200518";
String value = lockServiceRedis.lock(key);
try {
if (value != null) {
System.out.println(Thread.currentThread().getName() + " lock key = " + key + " success! ");
Thread.sleep(2 * 1000);
} else {
System.out.println(Thread.currentThread().getName() + " lock key = " + key + " failure! ");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (value == null) {
value = "";
}
System.out.println(Thread.currentThread().getName() + " unlock key = " + key + " " + lockServiceRedis.unLock(key, value));
}
}
}).start();
}
}
}
网友评论