基于Redis的简单分布式锁

原创
2018/07/13 09:50
阅读数 382

      在项目开发中,常常会碰到需要做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();
    }

}

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
1 收藏
0
分享
返回顶部
顶部