1.先配置spring-data-redis

首先是依赖

    <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.8.4.RELEASE</version>
        </dependency>

redisconfig 配置类

springMVC 实现redis分布式锁 随笔 第1张
@Configuration
@PropertySource("classpath:irongbei.properties")
public class RedisConfig extends JCacheConfigurerSupport {
    @Autowired
    private Environment environment;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory fac = new JedisConnectionFactory();
        fac.setHostName(environment.getProperty("redis.host"));
        fac.setPort(Integer.parseInt(environment.getProperty("redis.port")));
        fac.setPassword(environment.getProperty("redis.password"));
        fac.setTimeout(Integer.parseInt(environment.getProperty("redis.timeout")));
//        fac.getPoolConfig().setMaxIdle(Integer.parseInt(environment.getProperty("redis.maxIdle")));
//        fac.getPoolConfig().setMaxTotal(Integer.parseInt(environment.getProperty("redis.maxTotal")));
//        fac.getPoolConfig().setMaxWaitMillis(Integer.parseInt(environment.getProperty("redis.maxWaitMillis")));
//        fac.getPoolConfig().setMinEvictableIdleTimeMillis(
//                Integer.parseInt(environment.getProperty("redis.minEvictableIdleTimeMillis")));
//        fac.getPoolConfig()
//                .setNumTestsPerEvictionRun(Integer.parseInt(environment.getProperty("redis.numTestsPerEvictionRun")));
//        fac.getPoolConfig().setTimeBetweenEvictionRunsMillis(
//                Integer.parseInt(environment.getProperty("redis.timeBetweenEvictionRunsMillis")));
//        fac.getPoolConfig().setTestOnBorrow(Boolean.parseBoolean(environment.getProperty("redis.testOnBorrow")));
//        fac.getPoolConfig().setTestWhileIdle(Boolean.parseBoolean(environment.getProperty("redis.testWhileIdle")));
        return fac;
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, String> redis = new RedisTemplate<>();
        // 设置redis的String/Value的默认序列化方式
        DefaultStrSerializer defaultStrSerializer = new DefaultStrSerializer();
        redis.setKeySerializer(defaultStrSerializer);
        redis.setValueSerializer(defaultStrSerializer);
        redis.setHashKeySerializer(defaultStrSerializer);
        redis.setHashValueSerializer(defaultStrSerializer);
        redis.setConnectionFactory(redisConnectionFactory);
        redis.afterPropertiesSet();
        return redis;
    }
}

 class DefaultStrSerializer implements RedisSerializer<Object> {
    private final Charset charset;

    public DefaultStrSerializer() {
        this(Charset.forName("UTF8"));
    }

    public DefaultStrSerializer(Charset charset) {
        Assert.notNull(charset, "Charset must not be null!");
        this.charset = charset;
    }


    @Override
    public byte[] serialize(Object o) throws SerializationException {
        return o == null ? null : String.valueOf(o).getBytes(charset);
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        return bytes == null ? null : new String(bytes, charset);

    }
}
View Code

redisLock类 分布式锁实现的类

@Component
public class RedisLock {

    private static final Logger log = LoggerFactory.getLogger(RedisLock.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     *
     * @param key
     * @param value 当前时间+超时时间
     * @return
     */
    public boolean lock(String key,String value){

        if(redisTemplate.opsForValue().setIfAbsent(key,value)){
            log.info(" [Redis分布式锁] key:[{}] 获取到锁",key);
            return true;
        }
        //oldvalue  俩个线程都返回A
        String currentValue = redisTemplate.opsForValue().get(key);
        //如果锁过期->这里如果一个key的value时间是小于当前当前时间 那就是过期了,如果大于当前时间才没有过期
        if(StringUtils.isNotEmpty(currentValue) && Long.parseLong(currentValue) <System.currentTimeMillis()){

            //获取上一个锁的时间
            //第一个线程获取上一个oldvalue 然后设置一个新的值进去 第二个线程就获取到是新的值.
            String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
            //3 这一步就只有第一个线程能匹配到了 第二个线程就获取不到了
            if(StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue)){
                log.info(" [Redis分布式锁] key:[{}] 获取到锁",key);
                return true;
            }

        }

        return false;

    }

    /**
     * 解锁
     * @param key
     * @param value
     */
    public void unlock(String key ,String value){
        try {
            String currentValue = redisTemplate.opsForValue().get(key);
            if(StringUtils.isNotEmpty(currentValue) && currentValue.equals(value)){
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Exception e) {
            log.error(" [redis分布式锁] 解锁异常, {} ",e);
        }


    }
}

测试类:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"/spring-context.xml","/spring-context-jedis.xml","/spring-context-shiro.xml"})
public class RedisLockTest {
    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolExecutor taskExecutor;


    @Autowired
    private RedisLock redisLock;
    private long timeout = 5*1000;

    private static  final Logger logger =LoggerFactory.getLogger(RedisLockTest.class);

    @Test
    public void  test (){
        for (int i = 0; i <200 ; i++) {
            taskExecutor.execute(()->{
                String time = String.valueOf(System.currentTimeMillis()+timeout);
                if(!redisLock.lock("testlock",time)){
                    logger.info("哎呦喂..人太多了 在排队中..");
                   return;
                }else {
                    try {
                        Thread.sleep(4000);
                        redisLock.unlock("testlock",time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            });
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }
}

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄