基于Redis的分布式锁

import com.again.common.service.RedisService;
import java.util.concurrent.locks.Lock;

/**
 * 基于redis的setnx()方法+get()方法+getSet()实现的分布式锁
 */
public class RedisDistributedLock {

    private RedisService jedis;
    private String LOCK_KEY = "Rlock_test_lock";
    private Lock lock;                  // 避免同一台机器上多个线程同时获取分布式锁
    private int RETRY_TIME = 10 * 1000; // 等待分布式锁的超时时间
    private int EXPIRE_TIME = 30 * 1000;// 分布式锁的过期时间
    private boolean locked;
    private long lockValue;

    public RedisDistributedLock(RedisService jedis, String LOCK_KEY, Lock lock, int RETRY_TIME, int EXPIRE_TIME) {
        this.jedis = jedis;
        this.LOCK_KEY = LOCK_KEY;
        this.lock = lock;
        this.RETRY_TIME = RETRY_TIME;
        this.EXPIRE_TIME = EXPIRE_TIME;
    }

    public RedisDistributedLock(RedisService jedis, String LOCK_KEY, Lock lock) {
        this.jedis = jedis;
        this.LOCK_KEY = LOCK_KEY;
        this.lock = lock;
    }

    public boolean lock() {
        lock.lock();
        int retryTime = RETRY_TIME;
        try {
            while (retryTime > 0) {
                lockValue = System.currentTimeMillis() + EXPIRE_TIME + 1; // 锁的过期时间
                String lockValueStr = String.valueOf(lockValue);
                // 判断能否获取锁
                if (jedis.setnx(LOCK_KEY, lockValueStr) == 1) {
                    // 成功获取锁
                    locked = true;
                    return locked;
                }
                String currLockVal = jedis.get(LOCK_KEY);
                // 判断锁是否已经失效
                if (currLockVal != null && Long.valueOf(currLockVal) < System.currentTimeMillis()) {
                    // 锁已经失效,使用getset设置最新的过期时间
                    String oldLockVal = jedis.getSet(LOCK_KEY, lockValueStr);
                    // 判断锁是否已经被抢占
                    if (oldLockVal != null && oldLockVal.equals(currLockVal)) {
                        locked = true;
                        return locked;
                    }
                }
                retryTime -= 100;
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public void unlock() {
        try {
            if (locked) {
                String currLockVal = jedis.get(LOCK_KEY);
                // 只能释放自己加的锁,根据 currLockVal与lockValue是否相等 来判断此时redis中的锁是否是自己加上的。
                // 若currLockVal与lockValue不相等,则说明之前在redis中加的锁已经过期了,之后其它机器上又获得了redis中的锁。
                if (currLockVal != null && Long.valueOf(currLockVal) == lockValue) {
                    jedis.del(LOCK_KEY);
                    locked = false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}


你可能感兴趣的:(NoSql,分布式)