zoukankan      html  css  js  c++  java
  • 基于redis实现的分布式锁


    RedisLockHelper.java

    
    /**
     * Created by BingZhong on 2017/7/29.
     *
     * 基于Redis实现的分布式锁
     */
    public final class RedisLockHelper {
    
        private static Logger logger = LoggerFactory.getLogger(RedisLockHelper.class);
    
        /**
         * redis操作帮助类,可以是其他封装了redis操作的类
         */
        private RedisHelper redisHelper;
    
        public static final long DEFAULT_TIMEOUT = 30 * 1000;
    
        public static final long DEFAULT_SLEEP_TIME = 100;
    
        private RedisLockHelper(RedisHelper redisHelper) {
            this.redisHelper = redisHelper;
        }
    
        public static RedisLockHelper getInstance(RedisHelper redisHelper) {
            return new RedisLockHelper(redisHelper);
        }
    
        /**
         * 创建锁
         *
         * @param mutex     互斥量
         * @param timeout   锁的超时时间
         * @param sleepTime 线程自旋尝试获取锁时的休眠时间
         * @param timeUnit  时间单位
         */
        public RedisLock newLock(String mutex, long timeout, long sleepTime, TimeUnit timeUnit) {
            logger.info("创建分布式锁,互斥量为{}", mutex);
            return new RedisLock(mutex, timeout, sleepTime, timeUnit);
        }
    
        public RedisLock newLock(String mutex, long timeout, TimeUnit timeUnit) {
            return newLock(mutex, timeout, DEFAULT_SLEEP_TIME, timeUnit);
        }
    
        public RedisLock newLock(String mutex) {
            return newLock(mutex, DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
        }
    
        public class RedisLock {
            /**
             * 用于创建redis健值对的键,相当于互斥量
             */
            private final String mutex;
    
            /**
             * 锁过期的绝对时间
             */
            private volatile long lockExpiresTime = 0;
    
            /**
             * 锁的超时时间
             */
            private final long timeout;
    
            /**
             * 每次循环获取锁的休眠时间
             */
            private final long sleepTime;
    
            /**
             * 锁的线程持有者
             */
            private volatile Thread lockHolder = null;
    
            private final ReentrantLock threadLock = new ReentrantLock();
    
            public RedisLock(String mutex, long timeout, long sleepTime, TimeUnit timeUnit) {
                this.mutex = mutex;
                this.timeout = timeUnit.toMillis(timeout);
                this.sleepTime = timeUnit.toMillis(sleepTime);
            }
    
            /**
             * 加锁,将会一直尝试获取锁,直到超时
             */
            public boolean lock(long acquireTimeout, TimeUnit timeUnit) throws InterruptedException {
                acquireTimeout = timeUnit.toMillis(acquireTimeout);
                long acquireTime = acquireTimeout + System.currentTimeMillis();
                threadLock.tryLock(acquireTimeout, timeUnit);
                try {
                    while (true) {
                        boolean hasLock = tryLock();
                        if (hasLock) {
                            //获取锁成功
                            return true;
                        } else if (acquireTime < System.currentTimeMillis()) {
                            break;
                        }
                        Thread.sleep(sleepTime);
                    }
                } finally {
                    if (threadLock.isHeldByCurrentThread()) {
                        threadLock.unlock();
                    }
                }
    
                return false;
            }
    
            /**
             * 尝试获取锁,无论是否获取到锁都将直接返回而不会阻塞
             * 不支持重入锁
             */
            public boolean tryLock() {
                if (lockHolder == Thread.currentThread()) {
                    throw new IllegalMonitorStateException("不支持重入锁");
                }
                long currentTime = System.currentTimeMillis();
                String expires = String.valueOf(timeout + currentTime);
                //尝试设置互斥量
                if (redisHelper.setNx(mutex, expires) > 0) {
                    setLockStatus(expires);
                    return true;
                } else {
                    String currentLockTime = redisHelper.get(mutex);
                    //检查锁是否超时
                    if (Objects.nonNull(currentLockTime) && Long.parseLong(currentLockTime) < currentTime) {
                        //获取旧的锁时间并设置互斥量
                        String oldLockTime = redisHelper.getSet(mutex, expires);
                        //判断获取到的旧值是否一致,不一致证明已经有另外的进程(线程)成功获取到了锁
                        if (Objects.nonNull(oldLockTime) && Objects.equals(oldLockTime, currentLockTime)) {
                            setLockStatus(expires);
                            return true;
                        }
                    }
    
                    return false;
                }
            }
    
            /**
             * 该锁是否被锁住
             */
            public boolean isLock() {
                String currentLockTime = redisHelper.get(mutex);
                //存在互斥量且锁还为过时即锁住
                return Objects.nonNull(currentLockTime) && Long.parseLong(currentLockTime) > System.currentTimeMillis();
            }
    
            public String getMutex() {
                return mutex;
            }
    
            /**
             * 解锁
             */
            public boolean unlock() {
                //只有锁的持有线程才能解锁
                if (lockHolder == Thread.currentThread()) {
                    //判断锁是否超时,没有超时才将互斥量删除
                    if (lockExpiresTime > System.currentTimeMillis()) {
                        redisHelper.del(mutex);
                        logger.info("删除互斥量[{}]", mutex);
                    }
                    lockHolder = null;
                    logger.info("释放[{}]锁成功", mutex);
    
                    return true;
                } else {
                    throw new IllegalMonitorStateException("没有获取到锁的线程无法执行解锁操作");
                }
            }
    
            private void setLockStatus(String expires) {
                lockExpiresTime = Long.parseLong(expires);
                lockHolder = Thread.currentThread();
                logger.info("获取[{}]锁成功", mutex);
            }
        }
    }
    
    
  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/qixidi/p/10213554.html
Copyright © 2011-2022 走看看