zoukankan      html  css  js  c++  java
  • 基于redis集群实现的分布式锁,可用于秒杀,定时器。

    在分布式系统中,经常会出现需要竞争同一资源的情况,使用redis可以实现分布式锁。

    前提:redis集群已经整合项目,并且可以直接注入JedisCluster使用:

        @Autowired
        private JedisCluster jedisCluster;

    1. 新建RedisLockManger分布式锁管理器,并且如上注入 JedisCluster :

    package com.jarfk.util.redis;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.JedisCluster;
    
    import javax.annotation.PostConstruct;
    import java.util.concurrent.TimeUnit;
    
    /**
     * redis集群分布式锁管理器,支持对单个资源加锁解锁,或给一批资源的批量加锁及解锁
     * Created by Administrator on 2017/10/12 0012.
     */
    @Component
    public class RedisLockManger {
        private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockManger.class);
    
        //设置3秒过期
        private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3;
    
        //    private static final int DEFAULT_BATCH_EXPIRE_TIME = 6;
    
        //static的变量无法注解
        @Autowired
        private JedisCluster jc;
    
        private static RedisLockManger lockManger;
    
        public RedisLockManger() {
        }
    
        @PostConstruct
        private void init() {
            lockManger = this;
            lockManger.jc = this.jc;
        }
        /**
         * 获取锁 如果锁可用   立即返回true,  否则立即返回false,作为非阻塞式锁使用
         * @param key
         * @return
         */
        public boolean tryLock(String key/* , String value*/) {
            try {
                return tryLock(key, key, 0L, null);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return false;
        }
    
        /**
         * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false,作为阻塞式锁使用
         * @param key 锁键
         * @param value 被谁锁定
         * @param timeout 尝试获取锁时长,建议传递500,结合实践单位,则可表示500毫秒
         * @param unit,建议传递TimeUnit.MILLISECONDS
         * @return
         * @throws InterruptedException
         */
        public boolean tryLock(String key , String value , long timeout , TimeUnit unit) throws InterruptedException {
            //纳秒
            long begin = System.nanoTime();
            do {
                //LOGGER.debug("{}尝试获得{}的锁.", value, key);
                Long i = lockManger.jc.setnx(key, value);
                if (i == 1) {
                    lockManger.jc.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                    LOGGER.debug(value + "-成功获取{}的锁,设置锁过期时间为{}秒 ", key, DEFAULT_SINGLE_EXPIRE_TIME);
                    return true;
                } else {
                    // 存在锁 ,但可能获取不到,原因是获取的一刹那间
    //                String desc = lockManger.jc.get(key);
    //                LOGGER.error("{}正被{}锁定.", key, desc);
                } if (timeout == 0) {
                    break;
                }
                //在其睡眠的期间,锁可能被解,也可能又被他人占用,但会尝试继续获取锁直到指定的时间
                Thread.sleep(100);
            } while ((System.nanoTime() - begin) < unit.toNanos(timeout));
            //因超时没有获得锁
            return false;
        }
    
        /**
         * 释放单个锁
         * @param key 锁键
         */
        public void unLock(String key/*, String value*/) {
            lockManger.jc.del(key);
            LOGGER.debug("{}锁被{}释放 .", key, key);
        }
    }

    2. 使用示例:

    首先在需要加锁的地方注入分布式锁管理器:

        @Autowired
        private RedisLockManger redisLock;

    然后调用即可,如:

            if (redisLock.tryLock("statusCheck")) { //此处代码是锁上的
                logger.debug("-----------------------:10秒执行一次!每次只有一个程序运行");
                //释放锁,正常情况下,此处代码要注释掉,以免锁被释放,需要释放时可以根据自己逻辑的需要 
                //redisLock.unLock("statusCheck");
            }

    首先注入需要的

  • 相关阅读:
    MySQL迁移升级解决方案
    Python json和simplejson的使用
    ASP.NET使用Memcached高缓存实例的初级介绍
    Spring Cloud Stream在同一通道根据消息内容分发不同的消费逻辑
    JS高级---函数的几个成员
    JS高级---bind方法的使用
    JS高级---bind方法
    JS高级---总结apply和call方法的使用
    JS高级---apply和call都可以改变this的指向
    JS高级---复习
  • 原文地址:https://www.cnblogs.com/007sx/p/7655057.html
Copyright © 2011-2022 走看看