用redis实现分布式锁

分布式部署中不可避免用到分布式锁,目前比较常用的实现方式一般有基于数据库的乐观锁、基于redis的分布式锁和基于zookeeper的分布式锁。本文只说redis的实现方式,使用jedis作为连接器。

比较简单,直接上代码吧。

 

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;

    }

}

 

调用方法

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

 

参考网上一些资料改造一下,比较简单,供大家参考。。。

 

posted @ 2018-01-16 12:00  卒子  阅读(350)  评论(0编辑  收藏  举报