简单实现了一个基于redis的分布式锁,存在bug...
2017-06-06 00:00
751 查看
直接上代码
中间存在一个bug,可能导致死锁.import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import redis.clients.jedis.Jedis; import java.util.Objects; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** * Created by wenshiliang on 2017/6/5. * 不太可靠的基于redis的分布式锁 * setnx一个跟随jvm的uuid到redis,成功,认为占用锁成功,设置thread. * * 释放锁:判断是不是当前thread占用的,判断是不是当前jvm占用的,是,del redis key. * * * bug: 当异常退出jvm时,可能导致lock未释放.一般情况下设置了redis value的有效时长.如果在setnx后,expire前异常中断了jvm.可能会导致死锁. */ public class RedisLock { public static final int LOCK_DEATH_TIME = 300;//lock锁住时长,防止死锁,单位seconds private static final Logger LOGGER = LoggerFactory.getLogger(RedisLock.class); private final static String UID = UUID.randomUUID().toString(); private final static ConcurrentHashMap<RedisLock, Object> LOCK_MAP = new ConcurrentHashMap<>(); private RedisTemplate<String, String> redisTemplate; private Thread exclusiveOwnerThread; private String key; static { //钩子,退出jvm时,移除lock Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("redis lock shutdown hook"); LOCK_MAP.entrySet().forEach(entry -> { entry.getKey().forceRelease(); }); })); } public RedisLock(RedisTemplate<String, String> redisTemplate, String key) { this.redisTemplate = redisTemplate; this.key = key; } public void acquire() { int i=1; while (!acquire(1000)){ if(i++>300){ LOGGER.warn("lock acquire wait"); } }; } /** * 获得锁 * @param time 毫秒 * @return */ public boolean acquire(final long time) { if (Objects.equals(Thread.currentThread(), exclusiveOwnerThread)) { String result = redisTemplate.opsForValue().get(key); if (UID.equals(result)) { return true; } setExclusiveOwnerThread(null); } boolean flag = false; long start = System.currentTimeMillis(); while (!flag && start <= System.currentTimeMillis() + time) { flag = redisTemplate.execute(new RedisCallback<Boolean>() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { Jedis jedis = (Jedis) connection.getNativeConnection(); if (jedis.setnx(key, UID) == 1L) { jedis.expire(key, LOCK_DEATH_TIME);//300秒过期,防止死锁.如果在这步前jvm挂了,会导致一直死锁. LOCK_MAP.put(RedisLock.this,1); setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } }); } return flag; } public void release() { if (Objects.equals(Thread.currentThread(), exclusiveOwnerThread)) { String result = redisTemplate.opsForValue().get(key); if (UID.equals(result)) { LOCK_MAP.remove(this); setExclusiveOwnerThread(null); redisTemplate.delete(key); } } } protected void setExclusiveOwnerThread(Thread thread) { exclusiveOwnerThread = thread; } private void forceRelease() { String result = redisTemplate.opsForValue().get(key); if (UID.equals(result)) { LOCK_MAP.remove(this); setExclusiveOwnerThread(null); redisTemplate.delete(key); LOGGER.info("force release lock: " + key); } } }
相关文章推荐
- 基于Redis实现简单的分布式锁
- 基于Redis的分布式锁的简单实现
- [bigdata-119] 一个基于redis的简单分布式log系统
- 手把手教你实现一个基于Redis的分布式锁
- 基于Redis实现简单的分布式锁
- 2种基于简单定时任务实现分布式定时任务的技术解决方案(zookeeper、redis和内联MQ)
- 基于Redis实现简单的分布式锁
- 基于单点redis服务的分布式锁简单实现
- 一个简单的基于注解的 Controller (spring 2.5 annotation 方式实现mvc )
- 分布式锁与实现(一)基于Redis实现
- 基于python实现一个简单的神经网络
- Python 用Redis简单实现分布式爬虫的方法
- 基于express,MySQL,ejs实现的一个简单基本的网站后台管理应用
- 基于Redis实现分布式锁
- 基于C++实现一个简单的智能指针类
- 学习LSM(Linux security module)之四:一个基于LSM的简单沙箱的设计与实现
- 基于zookeeper简单实现分布式锁
- 基于Redis Lua脚本实现的分布式锁 | 日拱一卒
- 一个简单的基于注解的 Controller (spring 2.5 annotation 方式实现mvc )
- 采用Best effort 1pc + 回滚补偿机制实现的一个distributed transaction (分布式事务框架).基于dubbo rpc服务上实现。