创建redisson实例
public class Redisson implements RedissonClient {
/**
* Create sync/async Redisson instance with default config
*
* @return Redisson instance
*/
public static RedissonClient create() {
Config config = new Config();
// 单机
config.useSingleServer()
.setTimeout(1000000)
.setAddress("redis://127.0.0.1:6379");
// 主备
// config.useMasterSlaveConnection().setMasterAddress("127.0.0.1:6379").addSlaveAddress("127.0.0.1:6389").addSlaveAddress("127.0.0.1:6399");
// 哨兵
// config.useSentinelConnection().setMasterName("mymaster").addSentinelAddress("127.0.0.1:26389", "127.0.0.1:26379");
// 集群
// config.useClusterServers().addNodeAddress("127.0.0.1:7000");
return create(config);
}
/**
* Create sync/async Redisson instance with provided config
*
* @param config for Redisson
* @return Redisson instance
*/
public static RedissonClient create(Config config) {
org.redisson.Redisson redisson = new org.redisson.Redisson(config);
if (config.isReferenceEnabled()) {
redisson.enableRedissonReferenceSupport();
}
return redisson;
}
}
获取锁
public class Redisson implements RedissonClient {
@Override
public RLock getLock(String name) {
return new RedissonLock(connectionManager.getCommandExecutor(), name);
}
}
加锁、解锁
public interface RLock extends Lock, RLockAsync {
/**
* Acquires the lock.
*
* <p>If the lock is not available then the current thread becomes disabled for thread scheduling purposes
* and lies dormant until the lock has been acquired.
* <p>
* If the lock is acquired, it is held until <code>unlock</code> is invoked,
* or until leaseTime milliseconds have passed since the lock was granted - whichever comes first.
*
* @param leaseTime the maximum time to hold the lock after granting it,
* before automatically releasing it if it hasn't already been released by invoking <code>unlock</code>.
* If leaseTime is -1, hold the lock until explicitly unlocked.
* @param unit the time unit of the {@code leaseTime} argument
*/
void lock(long leaseTime, TimeUnit unit);
/**
* Unlocks lock independently of state
*
* @return <code>true</code> if lock existed and now unlocked otherwise <code>false</code>
*/
boolean forceUnlock();
}
加锁、解锁lua脚本:
public class RedissonLock {
/**
* KEYS[1] :需要加锁的key
* ARGV[1] :锁的超时时间,防止死锁
* ARGV[2] :锁的唯一标识
*
* 执行这段Lua脚本返回空,说明获取到锁;
* 如果返回一个long数值(表示锁剩余都过期时间),则表明锁已被占用。
*
* @param leaseTime
* @param unit
* @param threadId
* @param command
* @param <T>
* @return
*/
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
// 检查key是否已被占用,如果没有则设置超时时间及唯一标识,初始化value=1
"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; " +
// 锁重入的情况,判断锁的key field,一致的话,value加1
"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.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
/**
* KEYS[1] :需要加锁的key
* KEYS[2] :redis消息的ChannelName。一个锁唯一对应一个channelName: “redisson_lock__channel__{” + getName() + “}”
* ARGV[1] :reids消息体(1个字节),标记key已经解锁,通过redis的Subscribe唤醒其它订阅解锁消息的线程。
* ARGV[2] :锁的超时时间,防止死锁
* ARGV[3] :锁的唯一标识
*
* 执行这段Lua脚本返回空,说明当前线程并不是锁的持有者;
* 如果返回1表示锁释放成功;
* 如果返回0表示锁之前发生了重入,此时锁还没有真正地被释放,只是对计数器做了减1操作。
*
* @param threadId
* @return
*/
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
// 如果key和锁的唯一标识不匹配,则说明当前线程并没有持有锁,不能进行解锁操作。
"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
"return nil;" +
"end; " +
// key的value减1
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
// key的value大于0说明锁之前发生了重入,故此时不能删除key
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
// key的value等于0说明所有加过锁的地方都已经退出锁了,故此时需要删除key
"else " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end; " +
//
"return nil;",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));
}
}
获取RedLock
/**
* RedLock locking algorithm implementation for multiple locks.
* It manages all locks as one.
*
* @see <a href="http://redis.io/topics/distlock">http://redis.io/topics/distlock</a>
*
* @author Nikita Koksharov
*
*/
public class RedissonRedLock extends RedissonMultiLock {
/**
* Creates instance with multiple {@link RLock} objects.
* Each RLock object could be created by own Redisson instance.
*
* @param locks - array of locks
*/
public RedissonRedLock(RLock... locks) {
super(locks);
}
@Override
protected int failedLocksLimit() {
return locks.size() - minLocksAmount(locks);
}
protected int minLocksAmount(final List<RLock> locks) {
return locks.size()/2 + 1;
}
@Override
protected long calcLockWaitTime(long remainTime) {
return Math.max(remainTime / locks.size(), 1);
}
@Override
public void unlock() {
unlockInner(locks);
}
}
RedLock的加锁、解锁
public class RedissonMultiLock implements RLock {
final List<RLock> locks = new ArrayList<>();
public RedissonMultiLock(RLock... locks) {
if (locks.length == 0) {
throw new IllegalArgumentException("Lock objects are not defined");
}
this.locks.addAll(Arrays.asList(locks));
}
@Override
public void lock() {
try {
lockInterruptibly();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void lock(long leaseTime, TimeUnit unit) {
try {
lockInterruptibly(leaseTime, unit);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void unlock() {
List<RFuture<Void>> futures = new ArrayList<>(locks.size());
for (RLock lock : locks) {
futures.add(lock.unlockAsync());
}
for (RFuture<Void> future : futures) {
future.syncUninterruptibly();
}
}
protected void unlockInner(Collection<RLock> locks) {
List<RFuture<Void>> futures = new ArrayList<>(locks.size());
for (RLock lock : locks) {
futures.add(lock.unlockAsync());
}
for (RFuture<Void> unlockFuture : futures) {
unlockFuture.awaitUninterruptibly();
}
}
}