public class RedissonLock extends RedissonExpirable implements RLock {
private static final Logger log = LoggerFactory.getLogger(RedissonLock.class);
private static final ConcurrentMap EXPIRATION_RENEWAL_MAP = new ConcurrentHashMap();
protected long internalLockLeaseTime;
final UUID id;
final String entryName;
protected final LockPubSub pubSub;
final CommandAsyncExecutor commandExecutor;
private static final RedisCommand HGET;
public RedissonLock(CommandAsyncExecutor commandExecutor, String name) {
super(commandExecutor, name);
this.commandExecutor = commandExecutor;
this.id = commandExecutor.getConnectionManager().getId();
this.internalLockLeaseTime = commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout();
this.entryName = this.id + ":" + name;
this.pubSub = commandExecutor.getConnectionManager().getSubscribeService().getLockPubSub();
}
protected String getEntryName() {
return this.entryName;
}
String getChannelName() {
return prefixName("redisson_lock__channel", this.getName());
}
protected String getLockName(long threadId) {
return this.id + ":" + threadId;
}
public void lock() {
try {
this.lock(-1L, (TimeUnit)null, false);
} catch (InterruptedException var2) {
throw new IllegalStateException();
}
}
public void lock(long leaseTime, TimeUnit unit) {
try {
this.lock(leaseTime, unit, false);
} catch (InterruptedException var5) {
throw new IllegalStateException();
}
}
public void lockInterruptibly() throws InterruptedException {
this.lock(-1L, (TimeUnit)null, true);
}
public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
this.lock(leaseTime, unit, true);
}
private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
long threadId = Thread.currentThread().getId();
Long ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl != null) {
RFuture future = this.subscribe(threadId);
this.commandExecutor.syncSubscription(future);
try {
while(true) {
ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl == null) {
return;
}
if (ttl >= 0L) {
try {
this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} catch (InterruptedException var13) {
if (interruptibly) {
throw var13;
}
this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
}
} else if (interruptibly) {
this.getEntry(threadId).getLatch().acquire();
} else {
this.getEntry(threadId).getLatch().acquireUninterruptibly();
}
}
} finally {
this.unsubscribe(future, threadId);
}
}
}
private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
return (Long)this.get(this.tryAcquireAsync(leaseTime, unit, threadId));
}
private RFuture tryAcquireOnceAsync(long leaseTime, TimeUnit unit, long threadId) {
if (leaseTime != -1L) {
return this.tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_NULL_BOOLEAN);
} else {
RFuture ttlRemainingFuture = this.tryLockInnerAsync(this.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_NULL_BOOLEAN);
ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
if (e == null) {
if (ttlRemaining) {
this.scheduleExpirationRenewal(threadId);
}
}
});
return ttlRemainingFuture;
}
}
private RFuture tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
if (leaseTime != -1L) {
return this.tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
} else {
RFuture ttlRemainingFuture = this.tryLockInnerAsync(this.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
if (e == null) {
if (ttlRemaining == null) {
this.scheduleExpirationRenewal(threadId);
}
}
});
return ttlRemainingFuture;
}
}
public boolean tryLock() {
return (Boolean)this.get(this.tryLockAsync());
}
private void renewExpiration() {
RedissonLock.ExpirationEntry ee = (RedissonLock.ExpirationEntry)EXPIRATION_RENEWAL_MAP.get(this.getEntryName());
if (ee != null) {
Timeout task = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception {
RedissonLock.ExpirationEntry ent = (RedissonLock.ExpirationEntry)RedissonLock.EXPIRATION_RENEWAL_MAP.get(RedissonLock.this.getEntryName());
if (ent != null) {
Long threadId = ent.getFirstThreadId();
if (threadId != null) {
RFuture future = RedissonLock.this.renewExpirationAsync(threadId);
future.onComplete((res, e) -> {
if (e != null) {
RedissonLock.log.error("Can't update lock " + RedissonLock.this.getName() + " expiration", e);
} else {
if (res) {
RedissonLock.this.renewExpiration();
}
}
});
}
}
}
}, this.internalLockLeaseTime / 3L, TimeUnit.MILLISECONDS);
ee.setTimeout(task);
}
}
private void scheduleExpirationRenewal(long threadId) {
RedissonLock.ExpirationEntry entry = new RedissonLock.ExpirationEntry();
RedissonLock.ExpirationEntry oldEntry = (RedissonLock.ExpirationEntry)EXPIRATION_RENEWAL_MAP.putIfAbsent(this.getEntryName(), entry);
if (oldEntry != null) {
oldEntry.addThreadId(threadId);
} else {
entry.addThreadId(threadId);
this.renewExpiration();
}
}
protected RFuture renewExpirationAsync(long threadId) {
return this.commandExecutor.evalWriteAsync(this.getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('pexpire', KEYS[1], ARGV[1]); return 1; end; return 0;", Collections.singletonList(this.getName()), new Object[]{this.internalLockLeaseTime, this.getLockName(threadId)});
}
void cancelExpirationRenewal(Long threadId) {
RedissonLock.ExpirationEntry task = (RedissonLock.ExpirationEntry)EXPIRATION_RENEWAL_MAP.get(this.getEntryName());
if (task != null) {
if (threadId != null) {
task.removeThreadId(threadId);
}
if (threadId == null || task.hasNoThreads()) {
task.getTimeout().cancel();
EXPIRATION_RENEWAL_MAP.remove(this.getEntryName());
}
}
}
RFuture tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand command) {
this.internalLockLeaseTime = unit.toMillis(leaseTime);
return this.commandExecutor.evalWriteAsync(this.getName(), LongCodec.INSTANCE, command, "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; return redis.call('pttl', KEYS[1]);", Collections.singletonList(this.getName()), new Object[]{this.internalLockLeaseTime, this.getLockName(threadId)});
}
private void acquireFailed(long threadId) {
this.get(this.acquireFailedAsync(threadId));
}
protected RFuture acquireFailedAsync(long threadId) {
return RedissonPromise.newSucceededFuture((Object)null);
}
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
long time = unit.toMillis(waitTime);
long current = System.currentTimeMillis();
long threadId = Thread.currentThread().getId();
Long ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl == null) {
return true;
} else {
time -= System.currentTimeMillis() - current;
if (time <= 0L) {
this.acquireFailed(threadId);
return false;
} else {
current = System.currentTimeMillis();
RFuture subscribeFuture = this.subscribe(threadId);
if (!this.await(subscribeFuture, time, TimeUnit.MILLISECONDS)) {
if (!subscribeFuture.cancel(false)) {
subscribeFuture.onComplete((res, e) -> {
if (e == null) {
this.unsubscribe(subscribeFuture, threadId);
}
});
}
this.acquireFailed(threadId);
return false;
} else {
try {
time -= System.currentTimeMillis() - current;
if (time <= 0L) {
this.acquireFailed(threadId);
boolean var20 = false;
return var20;
} else {
boolean var16;
do {
long currentTime = System.currentTimeMillis();
ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl == null) {
var16 = true;
return var16;
}
time -= System.currentTimeMillis() - currentTime;
if (time <= 0L) {
this.acquireFailed(threadId);
var16 = false;
return var16;
}
currentTime = System.currentTimeMillis();
if (ttl >= 0L && ttl < time) {
this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} else {
this.getEntry(threadId).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
}
time -= System.currentTimeMillis() - currentTime;
} while(time > 0L);
this.acquireFailed(threadId);
var16 = false;
return var16;
}
} finally {
this.unsubscribe(subscribeFuture, threadId);
}
}
}
}
}
protected RedissonLockEntry getEntry(long threadId) {
return (RedissonLockEntry)this.pubSub.getEntry(this.getEntryName());
}
protected RFuture subscribe(long threadId) {
return this.pubSub.subscribe(this.getEntryName(), this.getChannelName());
}
protected void unsubscribe(RFuture future, long threadId) {
this.pubSub.unsubscribe((PubSubEntry)future.getNow(), this.getEntryName(), this.getChannelName());
}
public boolean tryLock(long waitTime, TimeUnit unit) throws InterruptedException {
return this.tryLock(waitTime, -1L, unit);
}
public void unlock() {
try {
this.get(this.unlockAsync(Thread.currentThread().getId()));
} catch (RedisException var2) {
if (var2.getCause() instanceof IllegalMonitorStateException) {
throw (IllegalMonitorStateException)var2.getCause();
} else {
throw var2;
}
}
}
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public boolean forceUnlock() {
return (Boolean)this.get(this.forceUnlockAsync());
}
public RFuture forceUnlockAsync() {
this.cancelExpirationRenewal((Long)null);
return this.commandExecutor.evalWriteAsync(this.getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if (redis.call('del', KEYS[1]) == 1) then redis.call('publish', KEYS[2], ARGV[1]); return 1 else return 0 end", Arrays.asList(this.getName(), this.getChannelName()), new Object[]{LockPubSub.UNLOCK_MESSAGE});
}
public boolean isLocked() {
return this.isExists();
}
public RFuture isLockedAsync() {
return this.isExistsAsync();
}
public RFuture isExistsAsync() {
return this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.EXISTS, new Object[]{this.getName()});
}
public boolean isHeldByCurrentThread() {
return this.isHeldByThread(Thread.currentThread().getId());
}
public boolean isHeldByThread(long threadId) {
RFuture future = this.commandExecutor.writeAsync(this.getName(), LongCodec.INSTANCE, RedisCommands.HEXISTS, new Object[]{this.getName(), this.getLockName(threadId)});
return (Boolean)this.get(future);
}
public RFuture getHoldCountAsync() {
return this.commandExecutor.writeAsync(this.getName(), LongCodec.INSTANCE, HGET, new Object[]{this.getName(), this.getLockName(Thread.currentThread().getId())});
}
public int getHoldCount() {
return (Integer)this.get(this.getHoldCountAsync());
}
public RFuture deleteAsync() {
return this.forceUnlockAsync();
}
public RFuture unlockAsync() {
long threadId = Thread.currentThread().getId();
return this.unlockAsync(threadId);
}
protected RFuture unlockInnerAsync(long threadId) {
return this.commandExecutor.evalWriteAsync(this.getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil;end; local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); return 0; else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end; return nil;", Arrays.asList(this.getName(), this.getChannelName()), new Object[]{LockPubSub.UNLOCK_MESSAGE, this.internalLockLeaseTime, this.getLockName(threadId)});
}
public RFuture unlockAsync(long threadId) {
RPromise result = new RedissonPromise();
RFuture future = this.unlockInnerAsync(threadId);
future.onComplete((opStatus, e) -> {
if (e != null) {
this.cancelExpirationRenewal(threadId);
result.tryFailure(e);
} else if (opStatus == null) {
IllegalMonitorStateException cause = new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: " + this.id + " thread-id: " + threadId);
result.tryFailure(cause);
} else {
this.cancelExpirationRenewal(threadId);
result.trySuccess((Object)null);
}
});
return result;
}
public RFuture lockAsync() {
return this.lockAsync(-1L, (TimeUnit)null);
}
public RFuture lockAsync(long leaseTime, TimeUnit unit) {
long currentThreadId = Thread.currentThread().getId();
return this.lockAsync(leaseTime, unit, currentThreadId);
}
public RFuture lockAsync(long currentThreadId) {
return this.lockAsync(-1L, (TimeUnit)null, currentThreadId);
}
public RFuture lockAsync(long leaseTime, TimeUnit unit, long currentThreadId) {
RPromise result = new RedissonPromise();
RFuture ttlFuture = this.tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.onComplete((ttl, e) -> {
if (e != null) {
result.tryFailure(e);
} else if (ttl == null) {
if (!result.trySuccess((Object)null)) {
this.unlockAsync(currentThreadId);
}
} else {
RFuture subscribeFuture = this.subscribe(currentThreadId);
subscribeFuture.onComplete((res, ex) -> {
if (ex != null) {
result.tryFailure(ex);
} else {
this.lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
}
});
}
});
return result;
}
private void lockAsync(long leaseTime, TimeUnit unit, RFuture subscribeFuture, RPromise result, long currentThreadId) {
RFuture ttlFuture = this.tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.onComplete((ttl, e) -> {
if (e != null) {
this.unsubscribe(subscribeFuture, currentThreadId);
result.tryFailure(e);
} else if (ttl == null) {
this.unsubscribe(subscribeFuture, currentThreadId);
if (!result.trySuccess((Object)null)) {
this.unlockAsync(currentThreadId);
}
} else {
final RedissonLockEntry entry = this.getEntry(currentThreadId);
if (entry.getLatch().tryAcquire()) {
this.lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
} else {
AtomicReference futureRef = new AtomicReference();
final Runnable listener = () -> {
if (futureRef.get() != null) {
((Timeout)futureRef.get()).cancel();
}
this.lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
};
entry.addListener(listener);
if (ttl >= 0L) {
Timeout scheduledFuture = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception {
if (entry.removeListener(listener)) {
RedissonLock.this.lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
}
}
}, ttl, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
});
}
public RFuture tryLockAsync() {
return this.tryLockAsync(Thread.currentThread().getId());
}
public RFuture tryLockAsync(long threadId) {
return this.tryAcquireOnceAsync(-1L, (TimeUnit)null, threadId);
}
public RFuture tryLockAsync(long waitTime, TimeUnit unit) {
return this.tryLockAsync(waitTime, -1L, unit);
}
public RFuture tryLockAsync(long waitTime, long leaseTime, TimeUnit unit) {
long currentThreadId = Thread.currentThread().getId();
return this.tryLockAsync(waitTime, leaseTime, unit, currentThreadId);
}
public RFuture tryLockAsync(long waitTime, long leaseTime, TimeUnit unit, long currentThreadId) {
RPromise result = new RedissonPromise();
AtomicLong time = new AtomicLong(unit.toMillis(waitTime));
long currentTime = System.currentTimeMillis();
RFuture ttlFuture = this.tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.onComplete((ttl, e) -> {
if (e != null) {
result.tryFailure(e);
} else if (ttl == null) {
if (!result.trySuccess(true)) {
this.unlockAsync(currentThreadId);
}
} else {
long el = System.currentTimeMillis() - currentTime;
time.addAndGet(-el);
if (time.get() <= 0L) {
this.trySuccessFalse(currentThreadId, result);
} else {
long current = System.currentTimeMillis();
AtomicReference futureRef = new AtomicReference();
final RFuture subscribeFuture = this.subscribe(currentThreadId);
subscribeFuture.onComplete((r, ex) -> {
if (ex != null) {
result.tryFailure(ex);
} else {
if (futureRef.get() != null) {
((Timeout)futureRef.get()).cancel();
}
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
this.tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
}
});
if (!subscribeFuture.isDone()) {
Timeout scheduledFuture = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception {
if (!subscribeFuture.isDone()) {
subscribeFuture.cancel(false);
RedissonLock.this.trySuccessFalse(currentThreadId, result);
}
}
}, time.get(), TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
});
return result;
}
private void trySuccessFalse(long currentThreadId, RPromise result) {
this.acquireFailedAsync(currentThreadId).onComplete((res, e) -> {
if (e == null) {
result.trySuccess(false);
} else {
result.tryFailure(e);
}
});
}
private void tryLockAsync(AtomicLong time, long leaseTime, TimeUnit unit, RFuture subscribeFuture, RPromise result, long currentThreadId) {
if (result.isDone()) {
this.unsubscribe(subscribeFuture, currentThreadId);
} else if (time.get() <= 0L) {
this.unsubscribe(subscribeFuture, currentThreadId);
this.trySuccessFalse(currentThreadId, result);
} else {
long curr = System.currentTimeMillis();
RFuture ttlFuture = this.tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.onComplete((ttl, e) -> {
if (e != null) {
this.unsubscribe(subscribeFuture, currentThreadId);
result.tryFailure(e);
} else if (ttl == null) {
this.unsubscribe(subscribeFuture, currentThreadId);
if (!result.trySuccess(true)) {
this.unlockAsync(currentThreadId);
}
} else {
long el = System.currentTimeMillis() - curr;
time.addAndGet(-el);
if (time.get() <= 0L) {
this.unsubscribe(subscribeFuture, currentThreadId);
this.trySuccessFalse(currentThreadId, result);
} else {
final long current = System.currentTimeMillis();
final RedissonLockEntry entry = this.getEntry(currentThreadId);
if (entry.getLatch().tryAcquire()) {
this.tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
} else {
AtomicBoolean executed = new AtomicBoolean();
AtomicReference futureRef = new AtomicReference();
final Runnable listener = () -> {
executed.set(true);
if (futureRef.get() != null) {
((Timeout)futureRef.get()).cancel();
}
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
this.tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
};
entry.addListener(listener);
long t = time.get();
if (ttl >= 0L && ttl < time.get()) {
t = ttl;
}
if (!executed.get()) {
Timeout scheduledFuture = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception {
if (entry.removeListener(listener)) {
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
RedissonLock.this.tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
}
}
}, t, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
}
});
}
}
static {
HGET = new RedisCommand("HGET", ValueType.MAP_VALUE, new IntegerReplayConvertor(0));
}
public static class ExpirationEntry {
private final Map threadIds = new LinkedHashMap();
private volatile Timeout timeout;
public ExpirationEntry() {
}
public void addThreadId(long threadId) {
Integer counter = (Integer)this.threadIds.get(threadId);
if (counter == null) {
counter = 1;
} else {
counter = counter + 1;
}
this.threadIds.put(threadId, counter);
}
public boolean hasNoThreads() {
return this.threadIds.isEmpty();
}
public Long getFirstThreadId() {
return this.threadIds.isEmpty() ? null : (Long)this.threadIds.keySet().iterator().next();
}
public void removeThreadId(long threadId) {
Integer counter = (Integer)this.threadIds.get(threadId);
if (counter != null) {
counter = counter - 1;
if (counter == 0) {
this.threadIds.remove(threadId);
} else {
this.threadIds.put(threadId, counter);
}
}
}
public void setTimeout(Timeout timeout) {
this.timeout = timeout;
}
public Timeout getTimeout() {
return this.timeout;
}
}
}
protected String getLockName(long threadId) {
# id是 UUID.randomUUID()
# threadId是线程编号
# 类似返回 d2518228-aad9-4fd8-b814-f450541cab3c:1
return this.id + ":" + threadId;
}
# 判断锁存在与否 LockKey,
if (redis.call('exists', KEYS[1]) == 0) then
## 如果不存在, 使用 hset命令加锁: hset LockKey d2518228-aad9-4fd8-b814-f450541cab3c:1 1
redis.call('hset', KEYS[1], ARGV[2], 1);
## 同时设置过期时间
redis.call('pexpire', KEYS[1], ARGV[1]);
## 返回空值, 结束此脚本
return nil;
end;
# 判断当前线程是否已持有锁
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
## 如果已持有锁, 递增重入锁次数
redis.call('hincrby', KEYS[1], ARGV[2], 1);
## 重置过期时间
redis.call('pexpire', KEYS[1], ARGV[1]);
## 返回空值, 结束此脚本
return nil;
end;
# 加锁失败, 返回当前锁的剩余时间给其它线程的请求者
return redis.call('pttl', KEYS[1]);
String getChannelName() {
# 类似返回 redisson_lock__channel:{LockKey}
return prefixName("redisson_lock__channel", this.getName());
}
# 获取锁, 如返回 null意思是成功抢到锁, 否者返回当前锁的剩余时间
Long ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl != null) {
# 当前请求者线程, 订阅释放锁消息
RFuture future = this.subscribe(threadId);
# 阻塞获取订阅结果
this.commandExecutor.syncSubscription(future);
try {
while(true) {
# 循环获取锁, 如返回 null意味着已抢到锁
ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl == null) {
return;
}
...
...
} finally {
# 取消订阅
this.unsubscribe(future, threadId);
}
...
...
# 判断当前线程是否没有锁
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
## 如果没有锁, 返回空值, 结束此脚本
return nil;
end;
# 将当前线程的锁数递减, 不能直接释放, 因为可能有重入锁
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
# 判断递减后是否还存在锁
if (counter > 0) then
# 当还存在锁, 重置过期时间
redis.call('pexpire', KEYS[1], ARGV[2]);
# 返回0, 结束此脚本
return 0;
else # 否者
# 如果递减后没有额外的锁, 删除锁键, 释放锁!
redis.call('del', KEYS[1]);
# 发送释放锁消息
redis.call('publish', KEYS[2], ARGV[1]);
# 返回1,结束此脚本
return 1;
end;
## 返回空值, 结束此脚本
return nil;
以上第二种情况, 可以用 Zookeeper实现分布式锁来防止锁失效情况, 因为 Zookeeper也支持主从结构, 它的主叫 leader(领导者), 从叫做 follower(跟随者), 与 Redis不同的是, 当加锁时, 将锁加到 leader后不会马上告知客户端成功信息, 而是先同步到 *所有的 follower的(半数以上)节点之后, 告知客户端.
Zookeeper集群架构是更多保证了 CAP中的(CP, 一致性和分区容错性), 而 Redis集群架构是更多保证了 CAP中的(AP, 可用性和分区容错性), 所以 Zookeeper牺牲了性能更多保证了一致
当然 Redis也可以通过类似的机制保证一致性, 如使用 Redisson的 getRedLock方法, 将多个锁合并成一个大锁, 并且统一的做加解锁. 不过这样做了已经牺牲了性能所以不如使用 Zookeeper
RAtomicLong atomicLong = redissonClient.getAtomicLong("MyAtomicLong");
System.out.println("value 1: " + atomicLong.get()); // value 1: 0
atomicLong.incrementAndGet();
System.out.println("value 2: " + atomicLong.get()); // value 2: 1
atomicLong.addAndGet(10L);
System.out.println("value 3: " + atomicLong.get()); // value 3: 11
System.out.println("value 4: " + atomicLong.getAndAdd(20L)); // value 4: 11
System.out.println("value 5: " + atomicLong.getAndIncrement()); // value 5: 31
System.out.println("value 6: " + atomicLong.getAndSet(30L)); // value 6: 32
System.out.println("value 7: " + atomicLong.getAndDelete()); // value 7: 30
System.out.println("value 8: " + atomicLong.get()); // value 8: 0
RBitSet bitset = redissonClient.getBitSet("log_20200719");
bitset.set(0L,true);
bitset.set(1L,true);
bitset.set(4L,true);
bitset.set(999L,true);
System.out.println("value 1: " + bitset.cardinality()); // value 1: 4
System.out.println("value 2: " + bitset.get(4L)); // value 2: true
System.out.println("value 3: " + bitset.get(5L)); // value 3: false
bitset.set(4L,false);
System.out.println("value 4: " + bitset.get(4L)); // value 4: false
System.out.println("value 5: " + bitset.cardinality()); // value 5: 3
bitset.set(8L,false);
System.out.println("value 6: " + bitset.cardinality()); // value 6: 3
//bitset.set(4294967295L,true); // 大约占512M左右内存空间, 4294967295L为最大数, 如超出此数值将会报错
bitset.set(1000000000L,true); // 大约占120M左右内存空间
System.out.println("value 7: " + bitset.cardinality()); // value 7: 4
bitset.clear();
System.out.println("value 8: " + bitset.cardinality()); // value 8: 0
RHyperLogLog log = redissonClient.getHyperLogLog("log_20200719");
log.add(0L);
log.add(2L);
log.add(3L);
log.add(3L);
System.out.println("count 1: " + log.count()); // count 1: 3
log.add(4294967296L);
log.add(999999999999999999L);
System.out.println("count 2: " + log.count()); // count 2: 5
log.delete();
System.out.println("count 3: " + log.count()); // count 3: 0
RBloomFilter bloomFilter = redissonClient.getBloomFilter("bloomFilter");
bloomFilter.tryInit(294967294L,0.03);
for (long i = 0; i < 1000L; i++) {
bloomFilter.add("全大爷 " + i);
}
System.out.println("全大爷 1: " + bloomFilter.contains("全大爷 " + 1)); // 全大爷 1: true
System.out.println("全大爷 1001: " + bloomFilter.contains("全大爷 " + 1001)); // 全大爷 1001: false
System.out.println("预计可插入数量: " + bloomFilter.getExpectedInsertions()); // 预计可插入数量: 294967294
System.out.println("容错率: " + bloomFilter.getFalseProbability()); // 容错率: 0.03
System.out.println("hash函数的个数: " + bloomFilter.getHashIterations()); // hash函数的个数: 5
System.out.println("已插入的对象的个数: " + bloomFilter.count()); // 已插入的对象的个数: 1000
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!