写一个关于lettuce redis的分布式锁的工具类,要防止被其他线程解锁
时间: 2024-02-05 13:11:44 浏览: 234
redis分布式锁工具类
下面是一个使用 Lettuce Redis 实现分布式锁的工具类,其中包含了防止被其他线程解锁的实现。
```java
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class RedisDistributedLock {
private static final long DEFAULT_LOCK_EXPIRATION_TIME = 30000;
private static final long DEFAULT_WAIT_TIMEOUT = 10000;
private static final long DEFAULT_RETRY_INTERVAL = 200;
private RedisCommands<String, String> redisCommands;
private StatefulRedisConnection<String, String> redisConnection;
private StatefulRedisClusterConnection<String, String> redisClusterConnection;
private String lockKey;
private String lockValue;
private long lockExpirationTime;
private long waitTimeout;
private long retryInterval;
private boolean isCluster;
public RedisDistributedLock(String redisUrl, String lockKey) {
this(redisUrl, lockKey, DEFAULT_LOCK_EXPIRATION_TIME, DEFAULT_WAIT_TIMEOUT, DEFAULT_RETRY_INTERVAL);
}
public RedisDistributedLock(String redisUrl, String lockKey, long lockExpirationTime, long waitTimeout, long retryInterval) {
RedisClient redisClient;
RedisClusterClient redisClusterClient;
if (redisUrl.contains(",")) {
redisClusterClient = RedisClusterClient.create(redisUrl);
redisClusterClient.setOptions(
ClusterClientOptions.builder()
.topologyRefreshOptions(
ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh()
.enableAllAdaptiveRefreshTriggers()
.refreshPeriod(Duration.ofSeconds(30))
.build())
.build());
this.redisClusterConnection = redisClusterClient.connect();
this.redisCommands = redisClusterConnection.sync();
this.isCluster = true;
} else {
redisClient = RedisClient.create(redisUrl);
this.redisConnection = redisClient.connect();
this.redisCommands = redisConnection.sync();
this.isCluster = false;
}
this.lockKey = lockKey;
this.lockExpirationTime = lockExpirationTime;
this.waitTimeout = waitTimeout;
this.retryInterval = retryInterval;
this.lockValue = UUID.randomUUID().toString();
}
public boolean acquireLock() {
long startTime = System.currentTimeMillis();
while (true) {
if (System.currentTimeMillis() - startTime > waitTimeout) {
return false;
}
if (isCluster) {
if (redisCommands.set(lockKey, lockValue, "NX", "PX", lockExpirationTime)) {
return true;
}
} else {
if (redisCommands.set(lockKey, lockValue, "NX", "PX", lockExpirationTime)) {
return true;
}
}
try {
Thread.sleep(retryInterval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public void releaseLock() {
if (isCluster) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
redisCommands.eval(script, RedisCommands.<String, String>newScript().withResultType(String.class),
new String[]{lockKey}, lockValue);
} else {
redisCommands.eval("if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end",
RedisCommands.<String, String>newScript().withResultType(String.class),
new String[]{lockKey}, lockValue);
}
}
public boolean isCluster() {
return isCluster;
}
public void close() {
if (isCluster) {
redisClusterConnection.close();
} else {
redisConnection.close();
}
}
}
```
使用示例:
```java
public static void main(String[] args) {
RedisDistributedLock lock = new RedisDistributedLock("redis://localhost:6379", "myLock");
if (lock.acquireLock()) {
try {
// do something
} finally {
lock.releaseLock();
}
}
lock.close();
}
```
在 acquireLock() 方法中,使用了一个 while 循环来不断尝试获取锁,直到成功或者超时。在 releaseLock() 方法中,使用了 Redis 的 Lua 脚本来判断是否可以解锁,防止被其他线程解锁。
需要注意的是,该工具类只能在单机或者 Redis 集群环境下使用,不支持 Redis Sentinel 模式。
阅读全文