redis实现分布式可重入锁

利用redis可以实现分布式锁,demo如下:

 1 /**
 2  * 保存每个线程独有的token
 3  */
 4     private static ThreadLocal<String> tokenMap = new ThreadLocal<>();
 5 
 6     /**
 7      * redis实现分布式可重入锁,并不保证在过期时间内完成锁定内的任务,需根据业务逻辑合理分配seconds
 8      * 
 9      * @param lock
10      *            锁的名称
11      * @param seconds
12      *            锁定时间,单位 秒
13      *  token
14      *            对于同一个lock,相同的token可以再次获取该锁,不相同的token线程需等待到unlock之后才能获取
15      * @return
16      */
17     public boolean lock(final String lock,final  int seconds) {
18         // @param token 对于同一个lock,相同的token可以再次获取该锁,不相同的token线程需等待到unlock之后才能获取
19         String token = tokenMap.get();
20         if (StringUtil.isBlank(token)) {
21             token = UUIDGenerator.getUUID();
22             tokenMap.set(token);
23         }
24         boolean flag = false;
25         Jedis client = null;
26         try {
27             client = jedisPool.getResource();
28             String ret = client.set(lock, token, "NX", "EX", seconds);
29             if (ret == null) {// 该lock的锁已经存在
30                // String origToken = client.get(lock);// 即使lock已经过期也可以
31                // if (token.equals(origToken)||origToken==null) {// token相同默认为同一线程,所以token应该尽量长且随机,保证不同线程的该值不相同
32                   //  ret = client.set(lock, token, "NX", "EX", seconds);//
33                   //  if ("OK".equalsIgnoreCase(ret))
34                    //     flag = true;
35                // }
ret=client.cas(lock,origToken,token,seconds);
if("OK".equalsIgnoreCase(ret)){
flag=true;
}
36 } else if ("OK".equalsIgnoreCase(ret)) 37 flag = true; 38 } catch (Exception e) { 39 logger.error(" lock{} 失败"); 40 throw new RedisException(e); 41 } finally { 42 if (client != null) 43 client.close(); 44 } 45 return flag; 46 } 47 48 /** 49 * redis可以保证lua中的键的原子操作 unlock:lock调用完之后需unlock,否则需等待lock自动过期 50 * 51 * @param lock 52 * token 53 * 只有线程已经获取了该锁才能释放它(token相同表示已获取) 54 */ 55 public void unlock(final String lock) { 56 Jedis client = null; 57 final String token = tokenMap.get(); 58 if (StringUtil.isBlank(token)) 59 return; 60 try { 61 client = jedisPool.getResource(); 62 final String script = "if redis.call(\"get\",\"" + lock + "\") == \"" + token + "\"then return redis.call(\"del\",\"" + lock + "\") else return 0 end "; 63 client.eval(script); 64 } catch (Exception e) { 65 logger.error(" unlock{} 失败"); 66 throw new RedisException(e); 67 } finally { 68 if (client != null) 69 client.close(); 70 } 71 72 } 73 74 public static void main(String[] args) { 75 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 76 final RedisUtil redis = ctx.getBean(RedisUtil.class); 77 for (int i = 0; i < 100; i++) { 78 new Thread(new Runnable() { 79 String key = "cheng"; 80 81 @Override 82 public void run() { 83 boolean lock = redis.lock(key, 30); 84 System.out.print(lock + "-"); 85 86 } 87 }).start(); 88 ; 89 } 90 // redis.unlock(key); 91 // ctx.close(); 92 }

 

  

运行main方法:

 结果:true-false-......false-

转载于:https://www.cnblogs.com/yoohot/p/6601075.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值