用redis實現分佈式鎖

分佈式部署中不可避免用到分佈式鎖,目前比較經常使用的實現方式通常有基於數據庫的樂觀鎖、基於redis的分佈式鎖和基於zookeeper的分佈式鎖。本文只說redis的實現方式,使用jedis做爲鏈接器。redis

比較簡單,直接上代碼吧。數據庫

 

public class PaasLock {
    private static final String KEY_NNXX = "NX";
    private static final String KEY_EXPX = "PX";
    private static final String KEY_SUCCESS = "OK";
    private static final String KEY_PREFIX = "paas.lock.";
    private static final Long KEY_RELEASE_NUM = 1L;  //影響redis行數
    private static Random RANDOM = new Random(100);
    private static final String REDIS_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    private RedisDao redisDao; //封裝jedis
    private String lockKey;

    public PaasLock() {
        //使用uuid生成不重複的key
        this(KEY_PREFIX + UUID.randomUUID().toString().replaceAll("-", ""));
    }

    //自定義key
    public PaasLock(String lockKey) {
        if (lockKey == null || lockKey.isEmpty()) throw new RuntimeException("lockKey is null or empty . . .");
        this.lockKey = KEY_PREFIX + lockKey;
        this.redisDao = SpringContexts.getBean(RedisDao.class);
    }


    /**
     * 獲取鎖
     *
     * @param requestId
     * @param expireTime 毫秒,鎖自己的超時時間
     * @param waitTime   毫秒,獲取鎖等待時間
     * @return true獲取成功,false獲取失敗
     */
    public boolean tryGetDistributedLock(String requestId, long expireTime, long waitTime) {
        long nanoTime = System.nanoTime();
        long timeOut = waitTime * 1000000; //納秒10^6 = 1毫秒

        try {
            //循環等待鎖釋放
            while (System.nanoTime() - nanoTime < timeOut) {
                String res = redisDao.set(this.lockKey, requestId, KEY_NNXX, KEY_EXPX, expireTime);
                if (KEY_SUCCESS.equals(res)) {
                    return true;// this.lock;
                }
                Thread.currentThread().sleep(5L, RANDOM.nextInt(30));
            }

        } catch (Exception ex) {
            throw new RuntimeException("locking error", ex);
        }
        return false;
    }

    /**
     * 釋放鎖
     *
     * @param requestId
     * @return
     */
    public boolean releaseDistributedLock(String requestId) {
        Object result = redisDao.eval(REDIS_SCRIPT, Collections.singletonList(this.lockKey), Collections.singletonList(requestId));
        if (KEY_RELEASE_NUM.equals(result)) { //只能釋放本身的鎖,防止被別的線程釋放
            System.out.println("release lock..,res=" + requestId);
            return true;
        }
        return false;

    }

}

 

調用方法dom

PaasLock lock = new PaasLock(); 
if (lock.tryGetDistributedLock(resId, 3000, 30000)) {
            try {
                do  .....
            } finally {
                lock.releaseDistributedLock(resId);
            }
   }
   else{
    ..... 其餘處理
   }

 

參考網上一些資料改造一下,比較簡單,供你們參考。。。分佈式

相關文章
相關標籤/搜索