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

 /**
* 保存每个线程独有的token
*/
private static ThreadLocal<String> tokenMap = new ThreadLocal<>(); /**
* redis实现分布式可重入锁,并不保证在过期时间内完成锁定内的任务,需根据业务逻辑合理分配seconds
*
* @param lock
* 锁的名称
* @param seconds
* 锁定时间,单位 秒
* token
* 对于同一个lock,相同的token可以再次获取该锁,不相同的token线程需等待到unlock之后才能获取
* @return
*/
public boolean lock(final String lock,final int seconds) {
// @param token 对于同一个lock,相同的token可以再次获取该锁,不相同的token线程需等待到unlock之后才能获取
String token = tokenMap.get();
if (StringUtil.isBlank(token)) {
token = UUIDGenerator.getUUID();
tokenMap.set(token);
}
boolean flag = false;
Jedis client = null;
try {
client = jedisPool.getResource();
String ret = client.set(lock, token, "NX", "EX", seconds);
if (ret == null) {// 该lock的锁已经存在
// 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;
}
} else if ("OK".equalsIgnoreCase(ret))
flag = true;
} catch (Exception e) {
logger.error(" lock{} 失败");
throw new RedisException(e);
} finally {
if (client != null)
client.close();
}
return flag;
} /**
* redis可以保证lua中的键的原子操作 unlock:lock调用完之后需unlock,否则需等待lock自动过期
*
* @param lock
* token
* 只有线程已经获取了该锁才能释放它(token相同表示已获取)
*/
public void unlock(final String lock) {
Jedis client = null;
final String token = tokenMap.get();
if (StringUtil.isBlank(token))
return;
try {
client = jedisPool.getResource();
final String script = "if redis.call(\"get\",\"" + lock + "\") == \"" + token + "\"then return redis.call(\"del\",\"" + lock + "\") else return 0 end ";
client.eval(script);
} catch (Exception e) {
logger.error(" unlock{} 失败");
throw new RedisException(e);
} finally {
if (client != null)
client.close();
} } public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
final RedisUtil redis = ctx.getBean(RedisUtil.class);
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
String key = "cheng"; @Override
public void run() {
boolean lock = redis.lock(key, 30);
System.out.print(lock + "-"); }
}).start();
;
}
// redis.unlock(key);
// ctx.close();
}

  

运行main方法:

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

最新文章

  1. 5分钟创建一个SpringBoot + Themeleaf的HelloWord应用
  2. [django]django+post+ajax+highcharts使用方法
  3. 【RabbitMQ】Publish/Subscribe
  4. Metronic学习之路
  5. HV和VM 内存性能测试对比结果
  6. delegate 集成在类中,还是单独写在.h文件中?
  7. Lisp: Common Lisp, Racket, Clojure, Emacs Lisp - Hyperpolyglot
  8. Log4NET 数据库
  9. js中的数组排序
  10. 《Netty5.0架构剖析和源码解读》【PDF】下载
  11. 洛谷 P1219 八皇后【经典DFS,温习搜索】
  12. LeetCode 字符串专题(一)
  13. SSZipArchive解压乱码
  14. Java8 方法引用
  15. 用highchaarts做股票分时图
  16. Oracle对象(视图、序列、索引)
  17. python with原理
  18. bzoj千题计划266:bzoj4872: [六省联考2017]分手是祝愿
  19. [转] impress.js学习
  20. Java操作Excel之Poi

热门文章

  1. codeforces 893D Credit Card 贪心 思维
  2. PL/SQL简单实现数据库的连接
  3. ibv_open_device()函数
  4. 通过邮箱发送html报表
  5. iscroll使用之页面卡顿问题
  6. 这是我对GET与POST的区别的回答
  7. Java 封装 HDFS API 操作
  8. 01_GIT基础、安装
  9. HTTP Status 500 - Request processing failed; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
  10. 【SqlServer】【问题收集】必须声明标量变量