一个Redis分布式锁的工具类(升级版)
来源:互联网 发布:软件实施培训 编辑:程序博客网 时间:2024/06/06 00:41
仅供个人记录
工具类:
RedisLock.java
import lombok.extern.slf4j.Slf4j;/** * 分布式锁工具类. * @author Pete.Lee Aug 29, 2017 3:23:41 PM */@Slf4jpublic class RedisLock { private static final int DEFAULT_ACQUIRY_RESOLUTION_MILLIS = 100; private final String lockKey; /** * 锁超时时间,防止线程在入锁以后,无限的执行等待 */ private int expireMsecs = 120 * 1000; /** * 锁等待时间,防止线程饥饿 */ private int timeoutMsecs = 20 * 1000; private volatile Boolean locked = false; private String myExpires = ""; public RedisLock(final String lockKey) { this.lockKey = lockKey + "_lock"; } public RedisLock(final String lockKey, final int timeoutMsecs) { this(lockKey); this.timeoutMsecs = timeoutMsecs; } public RedisLock(final String lockKey, final int timeoutMsecs, final int expireMsecs) { this(lockKey, timeoutMsecs); this.expireMsecs = expireMsecs; } public String getLockKey() { return lockKey; } /** * 获得 lock. 实现思路: 主要是使用了redis 的setnx命令,缓存了锁. reids缓存的key是锁的key,所有的共享, value是锁的到期时间(注意:这里把过期时间放在value了,没有时间上设置其超时时间) * 执行过程: 1.通过setnx尝试设置某个key的值,成功(当前没有这个锁)则返回,成功获得锁 2.锁已经存在则获取锁的到期时间,和当前时间比较,超时的话,则设置新的值 * @return true if lock is acquired, false acquire timeouted * @throws InterruptedException in case of thread interruption */ public synchronized Boolean lock() throws InterruptedException { int timeout = timeoutMsecs; while (timeout >= 0) { final long expires = System.currentTimeMillis() + expireMsecs + 1; final String expiresStr = String.valueOf(expires); // 锁到期时间 if (RedisUtil.setNx(lockKey, expiresStr)) { // lock acquired myExpires = expiresStr; locked = true; return true; } final String currentValueStr = RedisUtil.get(lockKey); // redis里的时间 if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { //判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的 // lock is expired final String oldValueStr = RedisUtil.getSet(lockKey, expiresStr); //获取上一个锁到期时间,并设置现在的锁到期时间, //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的 if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { //防止误删(覆盖,因为key是相同的)了他人的锁——这里达不到效果,这里值会被覆盖,但是因为什么相差了很少的时间,所以可以接受 //[分布式的情况下]:如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁 // lock acquired myExpires = expiresStr; locked = true; return true; } } timeout -= DEFAULT_ACQUIRY_RESOLUTION_MILLIS; /* 延迟100 毫秒, 这里使用随机时间可能会好一点,可以防止饥饿进程的出现,即,当同时到达多个进程, 只会有一个进程获得锁,其他的都用同样的频率进行尝试,后面有来了一些进行,也以同样的频率申请锁,这将可能导致前面来的锁得不到满足. 使用随机的等待时间可以一定程度上保证公平性 */ Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS); } return false; } public synchronized void unlock() { // 如果当前redis中的锁与上锁相同删除锁 if (myExpires.equals(RedisUtil.get(lockKey))) { if (locked) { RedisUtil.del(lockKey); locked = false; } } }}
RedisUtil.java
import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.util.ArrayList;import java.util.List;/** * redis 工具类. * @author Pete.Lee 2017/9/5 15:01 */@Slf4jpublic class RedisUtil { private static StringRedisTemplate template = ContextUtil.getBean("StringRedisTemplate", StringRedisTemplate.class); public static String get(final String key) { String obj = null; try { obj = template.execute((final RedisConnection c) -> { final StringRedisSerializer serializer = new StringRedisSerializer(); final byte[] data = c.get(serializer.serialize(key)); c.close(); return serializer.deserialize(data); }); } catch (Exception ex) { log.error("get redis error, key : {}", key); } return obj; } public static Boolean setNx(final String key, final String value) { Boolean b = false; try { b = template.execute((final RedisConnection c) -> { final StringRedisSerializer serializer = new StringRedisSerializer(); final Boolean success = c.setNX(serializer.serialize(key), serializer.serialize(value)); c.close(); return success; }); } catch (Exception e) { log.error("setNX redis error, key : {}", key); } return b; } public static String getSet(final String key, final String value) { String obj = null; try { obj = template.execute((final RedisConnection c) -> { final StringRedisSerializer serializer = new StringRedisSerializer(); final byte[] ret = c.getSet(serializer.serialize(key), serializer.serialize(value)); c.close(); return serializer.deserialize(ret); }); } catch (Exception ex) { log.error("setNX redis error, key : {}", key); } return obj; } public static Boolean del(final String key) { Boolean obj = null; try { obj = template.execute((final RedisConnection c) -> { final StringRedisSerializer serializer = new StringRedisSerializer(); return c.del(serializer.serialize(key)) > 0; }); } catch (Exception ex) { log.error("del redis error, key : {}", key); } return obj; } public static Long leftPush(final String key, final String value) { return template.opsForList().leftPush(key, value); } public static Long rightPush(final String key, final String value) { return template.opsForList().rightPush(key, value); } public static String leftPop(final String key) { return template.opsForList().leftPop(key); } public static String rightPop(final String key) { return template.opsForList().rightPop(key); } /*public RedisUtil() { final JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName("xxxx"); factory.setPort(6379); factory.setDatabase(2); factory.afterPropertiesSet(); template = new StringRedisTemplate(factory); template.afterPropertiesSet(); // System.out.println(template.boundValueOps("自增Key").increment(1)); }*/}
RedisConfigure.java
import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.datatype.joda.JodaModule;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;@Configuration@EnableCachingpublic class RedisConfigure { @Bean(name = "StringRedisTemplate") public StringRedisTemplate template(final RedisConnectionFactory factory) { final ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); om.registerModule(new JodaModule()); final Jackson2JsonRedisSerializer<?> serializer = new Jackson2JsonRedisSerializer<>(Object.class); serializer.setObjectMapper(om); final StringRedisTemplate template = new StringRedisTemplate(factory); template.setDefaultSerializer(serializer); template.setKeySerializer(serializer); template.setValueSerializer(serializer); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; }}
ContextUtil.java
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/** * 获取Bean工具类. * @author Pete.Lee 2017/9/5 15:02 */@Componentpublic class ContextUtil implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ContextUtil.context = applicationContext; } public static ApplicationContext getContext() { return context; } public static <T> T getBean(final String name, final Class<T> requiredType) { return context.getBean(name, requiredType); }}
YAML
spring: redis: host: 10.20.9.85 port: 6379 database: 0 password: pool.max-idle: 8 pool.min-idle: 4 pool.max-active: 16 pool.max-wait: -1
应用
final RedisLock lock = new RedisLock("lottery_result"); while (true) { try { if (lock.lock()) { // 需要加锁的代码 } } catch (InterruptedException ex) { } finally { lock.unlock(); } }
阅读全文
0 0
- 一个Redis分布式锁的工具类(升级版)
- redis的分布式锁
- Redis的分布式锁
- 使用redis写一个简单的分布式锁
- Redis实现分布式锁通用工具
- Redis实现分布式锁通用工具
- Codis 一个分布式的 Redis 解决方案
- 创建一个Redis工具类
- 【Redis深入】Redis分布式锁的实现
- redis分布式锁的实现
- redis实现的分布式锁
- 基于Redis的分布式锁
- redis分布式锁的实现
- 分布式锁的redis实现
- redis分布式锁的思考
- 基于Redis的分布式锁
- 基于redis的分布式锁
- 基于redis的分布式锁
- 10:有一门课不及格的学生
- Shade顶点函数vert和片元函数frag
- ffplay查看运动向量及宏块的显示情况
- 续上一篇,百度TTS(网络环境下语音引擎)的优化。可以在非网络情况下使用
- 解决日期转换json 报错问题
- 一个Redis分布式锁的工具类(升级版)
- 35、concurrent.futures模块与协程
- IDEA创建多个模块MavenSpringBoot项目
- 模拟考试1 BestCoder Round #2 TIANKENG’s restaurant
- 【微信小程序】获得用户input内容的方法
- jq中的delegate和each方法
- 线程安全单例模式
- D
- 使用MySqlWorkBench生成ER图步骤