• 用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{
        ..... 其他处理
       }

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

  • 相关阅读:
    教师派10
    教师派9
    简单理解socket(AF_INET&SOCK_STREAM,SOCK_DGRAM)
    Deepin安装MySQL(MariaDB)不提示设置密码问题(密码为空)
    经典排序算法-附python代码
    Linux虚拟环境virtualevn
    linux安装虚拟环境
    deepin安装虚拟环境virtualenv
    deepin安装虚拟环境virtualenv
    把握AFNet网络请求完成的正确时机
  • 原文地址:https://www.cnblogs.com/freeton/p/8295893.html
Copyright © 2020-2023  润新知