博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单实现了一个基于redis的分布式锁,存在bug...
阅读量:7008 次
发布时间:2019-06-28

本文共 3822 字,大约阅读时间需要 12 分钟。

hot3.png

直接上代码

中间存在一个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
LOCK_MAP = new ConcurrentHashMap<>(); private RedisTemplate
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
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
() { @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); } }}

转载于:https://my.oschina.net/superwen/blog/915734

你可能感兴趣的文章
ASP.NET web.config中<customErrors>节点说明
查看>>
《慕客网:IOS基础入门之Foundation框架初体验》学习笔记 <五> NSDicionary + NSMutableDictionary...
查看>>
jquery选择器 之 获取父级元素,子元素,同级元素
查看>>
Ajax注册表单用户名实时验证
查看>>
python使用正則表達式
查看>>
java遍历hashTable
查看>>
restful
查看>>
转:TestLink1.9.3测试用例:Excel转换XML工具<二>实现代码
查看>>
Python黑帽编程 4.1 Sniffer(嗅探器)之数据捕获(上)
查看>>
Elasticsearch基础教程
查看>>
P3389 【模板】高斯消元法
查看>>
zoj 2876 Phone List
查看>>
logback+slf4j作为日志系统
查看>>
Global Mapper如何加载在线地图
查看>>
黄聪:Wordpress中JQUERY链接平移效果
查看>>
反向代理服务器
查看>>
SharePoint 2010 网站备份还原简单介绍
查看>>
WebViewJavascriptBridge的基本原理
查看>>
IIS7 配置 PHP5.6
查看>>
Ubuntu 14.04 安装 boost 1_57_0
查看>>