`

redis分布式锁

 
阅读更多
redis是做为缓存的主流选择,这里主要拿它和memcached比较一下:

redis是单线程模型,没有锁的概念,不存在资源竞争,对于同一key是原子操作;memcached是多线程模型。利用自身的cas操作实现锁的操作(等同与乐观所,每一个key对应会产生一个64bit的标记,当某个线程更新key的值是会比较这个标记有没有变化,有变化则放弃更新);

redis中有一个setnx函数(set if not exist,当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0),可以利用它来实现一个简单的分布式锁;核心代码如下:
public class RedisLock implements Lock {

    @Autowired

    protected StringRedisTemplate redisTemplate;

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

    // lock flag stored in redis
    private static final String LOCKED = "TRUE";

    // timeout(ms)
    private static final long TIME_OUT = 30000;

    // lock expire time(s)
    public static final int EXPIRE = 60;

    // private Jedis jedis;
    private String key;

    // state flag
    private volatile boolean locked = false;

    private static ConcurrentMap<String, RedisLock> map = Maps.newConcurrentMap();

    public RedisLock(String key) {
        this.key = "_LOCK_" + key;
        redisTemplate = (StringRedisTemplate) ApplicationContextHolder.getBean("redisTemplate");
    }

    public static RedisLock getInstance(String key) {
        return map.getOrDefault(key, new RedisLock(key));
    }

    public void lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= 1000000;
        final Random r = new Random();
        try {
            while ((System.nanoTime() - nano) < timeout) {
                if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
                    redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
                    locked = true;
                    logger.debug("add RedisLock[" + key + "].");
                    break;
                }
                Thread.sleep(3, r.nextInt(500));
            }
        } catch (Exception e) {
        }
    }

    @Override
    public void unlock() {
        if (locked) {
            logger.debug("release RedisLock[" + key + "].");
            redisTemplate.delete(key);
        }
    }

    @Override
    public void lock() {
        lock(TIME_OUT);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public Condition newCondition() {
        return null;
    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
}

可以利用以上对象对共享资源进行锁定,功能类似于java内置锁ReentrantLock

其他常见用法:
if(getRedisClient().setnx("需要锁定的key", value)>0){
   return "重复调用";
}

以上利用setnx的特性实现表单重复提交的问题。避免请求密集造成数据重复
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics