wns9778.com_威尼斯wns.9778官网

热门关键词: wns9778.com,威尼斯wns.9778官网
wns9778.com > 计算机教程 > java中Redis锁的实现

原标题:java中Redis锁的实现

浏览次数:78 时间:2019-10-06

redis实现分布式锁,redis

清理邮件的时候发现之前看的一篇关于redis分布式锁实现的文章有人回复- -当时随意扫了眼文章,为了防止发生死锁,思路是使用setnx设置value为本地时间,然后获取锁失败时读取value进行时间比对。。然后我回复了下。。多台应用服务器存在时间不同步的问题。。

其实使用setnx时设置下redis过期时间简单方便,只是通常在应用程序内通过sdk做这项操作时由于赋值 设置过期不在同一原子性操作中。。所以很多人觉得不可行了。。那就直接使用lua脚本呗,简单方便,原子性操作,性能也OK。

加锁:aquire_lock_with_timeout.lua

if redis.call("exists",KEYS[1]) == 0 then
    local lockSrc = redis.call("setex",KEYS[1],unpack(ARGV))
    if lockSrc then
        return "1"
    end
        return "0"
end
return "-1"

释放锁:release_lock.lua

if redis.call("get",KEYS[1]) == ARGV[1] then
    local lockRelease = redis.call("del",KEYS[1])
        if lockRelease then
            return "1"
        end
            return "0"
end
return "-1"

java为例,加载两个lua脚本,然后简单加锁,释放锁

  @Bean
    @Qualifier("lockScript")
    public RedisScript<Integer> acquireLockWithTimeout() {
        DefaultRedisScript redisScript = new DefaultRedisScript();
        redisScript.setLocation(new ClassPathResource("redis/acquire_lock_with_timeout.lua"));
        redisScript.setResultType(Integer.class);
        return redisScript;
    }


    @Bean
    @Qualifier("unLockScript")
    public RedisScript<Integer> releaseLock() {
        DefaultRedisScript redisScript = new DefaultRedisScript();
        redisScript.setLocation(new ClassPathResource("redis/release_lock.lua"));
        redisScript.setResultType(Integer.class);
        return redisScript;
    }

    private Integer acquireTimeout;//资源占有锁的时间 秒s
    private Integer acquireInterval;//尝试获取锁的时限 ms
    private Integer lockTime;//尝试获取锁的时间间隔 ms

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    @Qualifier("lockScript")
    private RedisScript<Integer> acquireLockWithTimeout;
    @Autowired
    @Qualifier("unLockScript")
    private RedisScript<Integer> releaseLock;


    public String tryLock(String lockKey) {
        String lockValue = UUID.randomUUID().toString();
        Long endTime = System.currentTimeMillis()   acquireTimeout;
        while (System.currentTimeMillis() < endTime) {
            Integer lockResult = (Integer) redisTemplate.execute(acquireLockWithTimeout, Collections.singletonList(lockKey), lockTime, lockValue);
            if (lockResult.equals(1)) {
                return lockValue;
            } else {
                try {
                    Thread.sleep(acquireInterval);
                } catch (InterruptedException ex) {
                    continue;
                }
            }
        }
        return "";
    }

    public boolean releaseLock(String lockKey, String lockValue) {
        Integer releaseResult = (Integer) redisTemplate.execute(releaseLock, Collections.singletonList(lockKey), lockValue);
        if (releaseResult.equals(1)) {
            return true;
        }
        return false;
    }

当然java也有更复杂更丰富的组件 redisson

 

http://www.bkjia.com/Javabc/1305766.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javabc/1305766.htmlTechArticleredis实现分布式锁,rediswns9778.com, 清理邮件的时候发现之前看的一篇关于redis分布式锁实现的文章有人回复- -当时随意扫了眼文章,为了防止发生死锁...

wns9778.com 1

由于具体业务场景的需求,需要保证数据在分布式环境下的正确更新,所以研究了一下java中分布式锁的实现。

java分布式锁的实现方式主要有以下三种:

  1. 数据库实现的乐观锁
  2. Redis实现的分布式锁
  3. Zookeeper实现的分布式锁

其中,较常用的是前两种方式,但是数据库实现方式需要较多的数据库操作,所以最终选择的是用Redis实现分布式锁。

最初考虑分布式锁的数据安全性的时候,只考虑到两点。第一,Redis锁需要有一个超时时间,这样即便某个持有锁的节点挂了,也不到导致其他节点死锁,保证每个锁有一个uniqueId;第二,每个锁需要有一个UniqueId,确保当一个线程执行完一个任务去释放锁的时候释放的一定是自己的锁,否则可能存在一种场景,就是一个线程释放锁的时候,它的锁可能已经超时被释放了,而因为缺少一个UniqueId,它却释放了另一个线程的锁

基于以上两点的考虑,分别设计了获取锁和释放锁的api。

public interface DistributionLockService {
    /**
     * @param lockName the name of the lock
     * @param uniqueCode uniqueCode for the lock
     * @param expireTime expire time of lock
     * @return the result of get lock
     * */
    boolean getLock(String lockName, String uniqueCode, int expireTime);

    /**
     * @param lockName the name of the lock
     * @param uniqueCode uniqueCode for the lock
     * */
    void releaseLock(String lockName, String uniqueCode);

}

具体的实现代码如下:

   /**
     * @param lockName the name of the lock
     * @param uniqueCode uniqueCode for the lock
     * @param expireTime expire time of lock
     * @return the result of get lock
     * */
    @Override
    public boolean getLock(String lockName, String uniqueCode, int expireTime) {

        boolean isLock = false;
        try {
            Long result = jedis.setnx(lockName, uniqueCode);
            isLock = result == 1 ? true : false;
            if (isLock) {
                jedis.expire(lockName, expireTime);
            }
        } catch (Exception e){
            logger.error("DistributionLockService/getLock", e);
        }
        return isLock;
    }

    /**
     * @param lockName the name of the lock
     * @param uniqueCode uniqueCode for the lock
     * */
    @Override
    public void releaseLock(String lockName, String uniqueCode) {
        try {
            String tag = jedis.get(getKey(lockName));
            if (tag != null && tag.equals(uniqueCode))
                jedis.del(getKey(lockName));
        } catch (Exception e) {
            logger.error("DistributionLockService/releaseLock", e);
        }
    }

本文由wns9778.com发布于计算机教程,转载请注明出处:java中Redis锁的实现

关键词: wns9778.com

上一篇:php中xml解析函数xml_parser_createwns9778.com

下一篇:没有了