基于Redis的简单分布式锁

本文介绍了一种使用Redis实现分布式锁的简单方法,并提供了相应的Java代码示例。该方法包括设置锁、获取锁、检查锁的存在状态及释放锁等功能。

      在项目开发中,常常会碰到需要做lock锁的操作,而Redis又是最常用的分布式锁。在这提供一种简单的分布式锁实现,当然这里也有些考虑不周到,比如没实现公平与非公平锁、重入特性以及setNx及expire命令是分开的在极端(比如执行完A命令程序被kill -9了)造成死锁情况,没做redis集群情况下的高可用。

@Component
public class RedisOperation {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final long DEFAULT_EXPIRATION_TIMES = 600l;

    public void set(final String key, final String value) {
        this.set(key, value, DEFAULT_EXPIRATION_TIMES);
    }

    public void set(final String key, final String value, final long seconds) {
        redisTemplate.execute(new RedisCallback<Object>() {

            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                connection.setEx(redisTemplate.getStringSerializer().serialize(key), seconds, redisTemplate.getStringSerializer().serialize(value));
                return null;
            }

        });
    }

    public boolean setNx(final String key, final String value, final long seconds) {
        return redisTemplate.execute(new RedisCallback<Boolean>() {

            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] serializeKey = redisTemplate.getStringSerializer().serialize(key);
                boolean result = connection.setNX(serializeKey, redisTemplate.getStringSerializer().serialize(value));
                if (result) {
                    connection.expire(serializeKey, seconds);
                }
                return result;
            }
        });
    }

    public String get(final String key) {
        return redisTemplate.execute(new RedisCallback<String>() {

            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] byteKye = redisTemplate.getStringSerializer().serialize(key);
                if (connection.exists(byteKye)) {
                    byte[] byteValue = connection.get(byteKye);
                    String value = redisTemplate.getStringSerializer().deserialize(byteValue);
                    return value;
                }
                return null;
            }
        });
    }

    public boolean exists(final String key) {

        return redisTemplate.execute(new RedisCallback<Boolean>() {

            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.exists(redisTemplate.getStringSerializer().serialize(key));
            }
        });
    }

    public void delete(final String key) {
        redisTemplate.execute(new RedisCallback<Object>() {

            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                connection.del(redisTemplate.getStringSerializer().serialize(key));
                return null;
            }
        });
    }
}



@Component
public class DistributeLock {

    private static final Logger logger = LoggerFactory.getLogger(DistributeLock.class);

    public static final String REDIS_LOCK = "Demo:RedisLock:";

    @Autowired
    private RedisOperation redisOperation;


    public boolean lock(String key, long timeout, long waitTimeout) {
        return lock(key, timeout, waitTimeout, true);
    }

    /**
     *
     * @param key
     * @param timeout key超时时间 单位:秒
     * @param waitTimeout 等待获取锁时间  单位:毫秒
     * @param force 是否强依赖锁
     * @return
     *
     * @author hz15041240
     * @date 2017-8-30 下午5:20:14
     * @version
     */
    public boolean lock(String key, long timeout, long waitTimeout, boolean forced) {
        String lockKey = generateLockKey(key);
        long nanoWaitForLock = TimeUnit.MILLISECONDS.toNanos(waitTimeout);
        long start = System.nanoTime();
        try {
            do {
                if (redisOperation.setNx(lockKey, key, timeout)) {
                    logger.debug("add distributed lock succeed; lockKey:{}", lockKey);
                    return true;
                }
                TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(10, 80));
            } while ((System.nanoTime() - start) < nanoWaitForLock);
        } catch (Exception e) {
            logger.error(String.format("add distributed lock exception lockKey:%s", lockKey), e);
            unlock(lockKey);
            return !forced;
        }
        return false;
    }


    public void unlock(String key) {
        String lockKey = generateLockKey(key);
        try {
            redisOperation.delete(lockKey);
            logger.debug("remove distributed lock key:{} succeed", lockKey);
        } catch (Exception e) {
            logger.error(String.format("unlock exception lockKey:{} ", lockKey), e);
        }
    }

    public boolean isLock(String key) {
        String lockKey = generateLockKey(key);
        return redisOperation.exists(lockKey);
    }

    private String generateLockKey(String key) {
        return new StringBuilder(50).append(REDIS_LOCK).append(key).toString();
    }

}

 

转载于:https://my.oschina.net/woter/blog/1845708

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值