redis分布式锁的实现

redis做分布式锁的实现在网上找到的资料要么是实现方式比较复杂(redis版本比较旧的情况下有必要),要么是释放锁的时候有坑,所以自己实现了一个。
支持 redis 2.6.12以上版本。
同时也是redis官网推荐的一种实现方式,可以到http://redis.io/commands/set 看官网说法

package com.extracme.evcard.redis;

import java.util.UUID;

import redis.clients.jedis.Jedis;

/**
 * 
 * redis做分布式锁的实现
 * 
 * @author wu yibo
 */
public class JedisLock {

    private static final int ONE_SECOND = 1000;

    public static final int DEFAULT_EXPIRY_TIME_MILLIS = 5 * ONE_SECOND;

    private final Jedis jedis;

    private final String lockKey;
    private final int lockExpiryInMillis;
    private final UUID lockUUID;
    private boolean isLocked = false;

    
    /**
     * 生成锁对象
     * @param jedis
     * @param lockKey
     */
    public JedisLock(Jedis jedis, String lockKey) {
        this(jedis, lockKey, DEFAULT_EXPIRY_TIME_MILLIS);
    }

    /**
     * 生成锁对象
     * @param jedis
     * @param lockKey
     * @param expiryTimeMillis
     */
    public JedisLock(Jedis jedis, String lockKey, int expiryTimeMillis) {
        this(jedis, lockKey, expiryTimeMillis, UUID.randomUUID());
    }

    /**
     * 生成锁对象
     * @param jedis
     * @param lockKey
     * @param expiryTimeMillis
     * @param uuid
     */
    public JedisLock(Jedis jedis, String lockKey, int expiryTimeMillis, UUID uuid) {
        this.jedis = jedis;
        this.lockKey = lockKey;
        this.lockExpiryInMillis = expiryTimeMillis;
        this.lockUUID = uuid;;
    }
    
    
    public UUID getLockUUID() {
        return lockUUID;
    }

    
    public String getLockKey() {
        return lockKey;
    }

    /**
     * 加锁
     * @return
     * 
     * @author wu yibo
     */
    public synchronized boolean acquire() {
        return acquire(jedis);
    }

    /**
     * 加锁.
     * 这里是用的是redis 的set指令来实现加锁,详情请看:http://redis.io/commands/set
     * @param jedis
     * @return
     * 
     * @author wu yibo
     */
    protected synchronized boolean acquire(Jedis jedis) {
    	//nx表示:Only set the key if it does not already exist.
    	//ps表示:Set the specified expire time, in milliseconds。超时时间的单位是毫秒
    	if(!isLocked) {
    		isLocked = jedis.set(this.lockKey, this.lockUUID.toString(), "nx", "px", this.lockExpiryInMillis) != null;
    		return isLocked;
    	}
    	return false;
    }

    /**
     * 释放锁
     * 
     * @author wu yibo
     */
    public synchronized void release() {
        release(jedis);
    }

    /**
     * 释放锁
     * @param jedis
     * 
     * @author wu yibo
     */
    protected synchronized void release(Jedis jedis) {
    	if(this.isLocked) {
    		//使用eval指令执行 Lua 脚本
    		//如果redis中该key对应的值已经变掉了,不再执行删除指令。防止偶然情况下线程执行时间过长,导致释放锁的时候把其他线程的锁释放掉
    		jedis.eval("if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end", 1, this.lockKey, this.lockUUID.toString());
    	}
    	isLocked = false;
    }

    /**
     * 检查是否已经加锁
     * @return
     * 
     * @author wu yibo
     */
    public synchronized boolean isLocked() {
        return this.isLocked;
    }
}

猜你喜欢

转载自wuyibo126.iteye.com/blog/2327547