Redisson分布式锁

创建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();
        }
    }
}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值