程序员程序员技术栈消息中间件

如何实现分布式锁

2019-02-27  本文已影响1人  不孤独的字符串

谈及分布式,总会帮随着资源共享,然而有时候我们却希望只有一个线程对资源进行调度,不希望有多个线程同步调度,比如:每天晚上定时统计网站的访客量,这就涉及到了分布式锁。

因此我们要求这把锁要有以下的特性:

了解过Redis的人可能都知道Redis是单线程的,也就是对于同一个Redis实例,同一时刻只会处理一个请求。因为对于分布式架构不同机器共享同一资源,我们可以借助Redis实现分布式锁。使用Redis的SETNX和GETSET的配合使用则可实现分布式锁。

命令介绍

多个线程执行以下操作:

long currentTime = System.currentTimeMillis();
String lockTime = String.valueOf(currentTime + Lock_Timeout + 1);//锁的有效时间
Long result = jedisClient.setnx(key, lockTime);

如果 result == 1,说明该进程获得锁,setnx 将 key 的值设置为锁的超时时间(当前时间 + 锁的有效时间 + 1)。
如果 result == 0,说明其他进程已经获得了锁,进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。

考虑一种情况,如果进程获得锁后,断开了与 Redis 的连接(可能是进程挂掉,或者网络中断),如果没有有效的释放锁的机制,那么其他进程都会处于一直等待的状态,即出现“死锁”。对此,我们可以通过 getset 获取锁的一个最新的被改变的时间,与当前的时间进行比较,进而校验锁的一个最新的状态。

//获取锁
private boolean innerGetLock(String key){
    long currentTime = System.currentTimeMillis();
    String lockTime = String.valueOf(currentTime + Lock_Timeout + 1);//锁的有效时间
    Long result = jedisClient.setnx(key, lockTime);
    if (result == 1) {
        return true;
    } else {
        if (currentTime > Long.valueOf(jedisClient.get(key))){
            //当前时间已超过锁的有效时间,则判断是否有其他进程已获取到锁
            String preLockTimeDuration = jedisClient.getSet(key, lockTime);
            if (currentTime > Long.valueOf(preLockTimeDuration)) {
                return true;
            }
        }
        return false;
    }
}
上一篇下一篇

猜你喜欢

热点阅读