黑马程序员技术交流社区
标题:
[杭州校区]基于Redis实现分布式锁
[打印本页]
作者:
小江哥
时间:
2018-9-21 14:36
标题:
[杭州校区]基于Redis实现分布式锁
当多个进程不在同一个系统中,可以使用分布式锁控制多个进程对同一资源的访问。因为在分布式情况下(多JVM),线
程
A
和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。为了确保分布式锁可
用,我们至少要确保锁的实现同时满足以下四个条件:
1
、互斥性。在任意时刻,只有一个客户端能持有锁。
2
、防止死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
3
、容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
4
、加锁和解锁必须是同一个客户端。
工具类:
package com.it;
import
redis.clients.jedis.
Jedis
;
import
java.util.
Collections
;
/*使用前需导入如下依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>*/
public class
RedisTool
{
private
static
final
String
LOCK_SUCCESS
=
"OK"
;
//
NX
,意思是
SET
IF
NOT
EXIST
,即当key不存在时,我们进行
set
操作;若key已经存在,则不做任何操作。
private
static
final
String
SET_IF_NOT_EXIST
=
"NX"
;
//
PX
,意思是要给key加一个过期的设置,具体时间由下一个参数决定。
private
static
final
String
SET_WITH_EXPIRE_TIME
=
"PX"
;
private
static
final
Long
RELEASE_SUCCESS
=
1
L;
private
RedisTool
() {}
/**
* 尝试获取分布式锁
* @param jedis
Redis
客户端
* @param lockKey 锁:我们使用lockKey来当锁,因为key是唯一的。
* @param requestId 请求标识:分布式锁要满足解铃还须系铃人,在解锁的时候就可以以此为依据。
* requestId可以使用
UUID
.randomUUID().toString()方法生成。
* @param expireTime 超期时间:与“
SET_WITH_EXPIRE_TIME
”相呼应,代表key的过期时间。
* @
return
是否获取成功
*/
public
static
boolean tryGetDistributedLock(
Jedis
jedis,
String
lockKey,
String
requestId,
int
expireTime) {
String
result
= jedis.
set
(lockKey, requestId,
SET_IF_NOT_EXIST
,
SET_WITH_EXPIRE_TIME
, expireTime);
if
(
LOCK_SUCCESS
.equals(
result
)) {
return
true
;
}
return
false
;
}
/**
* 释放分布式锁
* @param jedis
Redis
客户端
* @param lockKey 锁
* @param requestId 请求标识
* @
return
是否释放成功
*/
public
static
boolean releaseDistributedLock(
Jedis
jedis,
String
lockKey,
String
requestId) {
/*
Lua
脚本说明:首先获取
KEYS
[
1
]对应的value,如果与
ARGV
[
1
]相等,则解锁。*/
String
script =
"if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
;
/*eval()方法是将
Lua
脚本交给
Redis
服务端执行,参数
KEYS
[
1
]赋值为lockKey,
ARGV
[
1
]赋值为requestId。*/
Object
result
= jedis.eval(script,
Collections
.singletonList(lockKey),
Collections
.singletonList(requestId));
if
(
RELEASE_SUCCESS
.equals(
result
)) {
return
true
;
}
return
false
;
}
}
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2