//利用redis 做分布式锁,此处实现需要根据实际场景进行优化. 好处是能分担数据库压力,但加锁的时间无法确定,需要另启线程进行延时处理//有个问题是 如果子线程延期6次后 主线程还未运行完毕 后续又会引发很多问题,这里可以 结合case1的乐观锁一起使用,用version字段双重保险,或许本来就应该这么做

static ThreadPoolExecutor pool = new ThreadPoolExecutor(10,20, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20));//这里最高并发限制50,我这里只有拿到锁了 才开启线程,早已有余,商品种类多,可以考虑加大队列/最大线程数

static{

pool.prestartAllCoreThreads();//预先创建核心线程

}

@GetMapping("/payII")public String testPayLockByRedis() throwsInterruptedException {//这里最好还是用userId

String name =Thread.currentThread().getName();for (int i = 0; i < 5; i++) {

Boolean lock= redisTemplate.opsForValue().setIfAbsent("1", name, 10000, TimeUnit.MILLISECONDS);if(lock) {

MyRunnable m= newMyRunnable(name);try{

pool.execute(m);

Goods goods= goodsMapper.selectByPrimaryKey(1);int storage =goods.getGoodsStorage();

goods.setGoodsStorage(storage- 1);if (goods.getGoodsStorage() >= 0) {

goodsMapper.updateByPrimaryKey(goods);

log.info("本次购买商品一件,剩余库存{}件", goods.getGoodsStorage());return "本次购买商品一件,剩余库存" + goods.getGoodsStorage() + "件";

}else{

log.info("库存不足");return "库存不足";

}

}catch(Exception e) {//这里抛出异常让事务回滚 , 异常部分让切面处理,优先级和事务一致,优先级一致事务先执行

throw newRunTimeException(e);

}finally{

m.flag= false;//这里的处理是因为 子线程在延时6次后,没有中断主线程的运行(这里无法中断,线程之间的运行是独立的,子线程抛出异常无法被主线程捕获,至多让thread设置一个//UncaughtExceptionHandler,在子线程抛出异常后,子线程内部自己进行捕获处理逻辑,然而还是不能影响主线程),既然如此,存在30s过后主线程仍未执行完毕的可能性,此时锁已易主,如果未//和version字段一起做保险处理,建议抛出异常,回滚事务

Object o = redisTemplate.opsForValue().get("1")if (o!=null &&name.equals(o.toString())) {

redisTemplate.delete("1");

}else{throw new RuntimeException("锁已失效")}

}

}else{continue;

}

}return "网络延迟,请稍后尝试";

}private class MyRunnable implementsRunnable {boolean flag = true;int time; //延期次数

String name; //线程name 用userId好些

private MyRunnable(String name) {this.name =name;}

@Overridepublic voidrun() {try{//给予一定的处理时间 再给任务做延时处理

Thread.sleep(2000);while (flag && time++ < 6) {

Object o= redisTemplate.opsForValue().get("1");//锁存在 且是自身加的锁 给锁延期

if (o != null && o.toString().equals(name) &&flag) {//如果出现判定通过

/*case1: 外面修改flag 这里延期成功 外面删除 并不影响

case2: 外面修改flag 删除 还未往redis 重新set 这里就延期 也不影响

case3: 外面修改flag 删除 其他用户往redis 重新set 这里再延期 好像也不会发生什么*/redisTemplate.expire("1", 10000, TimeUnit.MILLISECONDS);

System.out.println("延时一次");

}

Thread.sleep(3000);

}

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

java 防止超卖_实现防止超卖的几种方式相关推荐

  1. java消息幂等性实现_探讨一下实现幂等性的几种方式

    什么是幂等性? 对于同一笔业务操作,不管调用多少次,得到的结果都是一样的. 幂等性设计 我们以对接支付宝充值为例,来分析支付回调接口如何设计? 如果我们系统中对接过支付宝充值功能的,我们需要给支付宝提 ...

  2. Java版数据结构之单向链表 新增,有序新增的两种方式,修改和删除(CRUD)

    Java版数据结构之单向链表 CRUD Java版数据结构之单向链表 新增,有序新增的两种方式,修改和删除; 留了一个疑问; 我的代码仓库:https://github.com/zhuangbinan ...

  3. 查看weblogic Java版本_获取WebLogic版本号有以下几种方式

    获取WebLogic版本号有以下几种方式: 1.通过命令方式,具体操作方式如下 cd $MW_HOME\weblogicxx\server\bin $MW_HOME\weblogicxx\server ...

  4. java 文件下载详解_Java 从网上下载文件的几种方式实例代码详解

    废话不多说了,直接给大家贴代码了,具体代码如下所示: package com.github.pandafang.tool; import java.io.BufferedOutputStream; i ...

  5. java batch_Java EE 7 Batch中传递属性/参数的2种方式

    java batch 谈到Java EE 7批处理功能,有两种方法可以将属性/参数传递给块和批处理. 本快速指南向您展示了两种方式,在开发批处理Java EE 7方式时可能会经常使用它们. 1.运行前 ...

  6. java中map类型_Java中Map类型遍历的两种方式对比

    Java中Map类型是存储键值对数据的类型,在编程过程经常使用,进行遍历操作对于每个Java程序员都不会模式,下面总结两种常用的遍历方式(一种keySet,一种entrySet),通过对比让你明白使用 ...

  7. Java常见面试题:对象的访问定位的两种方式

    对象的访问定位的两种方式 java对象在访问的时候,我们需要通过java虚拟机栈的reference类型的数据去操作具体的对象. 由于reference类型在java虚拟机规范中只规定了一个对象的引用 ...

  8. java木马_Java校验上传图片文件是否含有木马的两种方式

    这两天开发一个app遇到了上传文件的安全问题,在这里记录下来,弥补自己只有鱼的记忆的缺陷,也希望有人能够提供更好的思路去解决文件上传的安全问题. 下面这个类是文件上传的公共方法,ToolUtils判断 ...

  9. java遍历一个map集合_Java遍历Map集合的四种方式

    Map 集合的遍历与 List 和 Set 集合不同.Map 有两组值,因此遍历时可以只遍历值的集合,也可以只遍历键的集合,也可以同时遍历.Map 以及实现 Map 的接口类(如 HashMap.Tr ...

  10. java get和post请求参数设置,Get和Post两种方式向指定地址提交表单

    做Java做了很多年,却总是把一些东西遗忘,过后再着急的找寻.最近,需要通过Java代码模拟一个表单提交,却怎么也想不起来如何封装数据了. 本篇主要描述Java网络参数传递,主要分为get和post两 ...

最新文章

  1. python语言怎么学-如何从零开始学习Python,python语言编程入门
  2. for循环里的if语句中break_Go语言极简教程 - 第五篇 控制语句
  3. 后台数据到mysql怎样保持实时更新_京东智联云MySQL数据库如何保障数据的可靠性?...
  4. 【iCore4 双核心板_ARM】例程二十:LWIP_TCP_CLIENT实验——以太网数据传输
  5. git show HEAD^num和个git show HEAD~num的区别
  6. css入门之head区设置
  7. 前端开发中JS调试技巧,你知道几种?用过几种?
  8. Dcmtk在PACS开发中的应用(基础篇) 第二章 打印影像(胶片) 作者 冷家锋
  9. 12月4日云栖精选夜读:乌镇AI论坛最全盘点:中国互联网半壁江山坐在了一起,他们怎么看AI...
  10. nginx rewrite php参数,Nginx泛域名解析及Rewrite重定向普通页面及带参数的页面
  11. 求指教,PSO算法跟踪光伏电池最大功率点
  12. nc 二次开发_金蝶云星空(K3CLOUD)和用友NC对比
  13. 文档数据库mongodb与列式数据库hbase详细比较
  14. 计算机考试PPT主题背景没换,2013职称计算机考试:搞定PPT背景设置中的问题
  15. UC Android官方下载,手机uc浏览器下载并安装-uc浏览器app最新版本v13.3.9.1119 安卓官方版 - 极光下载站...
  16. 常见游戏外挂分类及原理概述
  17. Mybatis注解@Results、@Result、@ResultMap
  18. Win10系统Ctrl键锁定无法使用解决方法
  19. Navigation Bar的背景图片设置
  20. 笔记本电脑的应用、维护、采购全攻略

热门文章

  1. 邮件服务器正常工作亮几个灯,光纤猫正常亮几个灯 光纤猫的灯都代表意思是什么【详解】...
  2. 用 Opencv 和 Python 对汪星人做模糊检测
  3. Win10怎么进Bios Win10系统进入BIOS界面的方法图文详解
  4. 【2017NOIP普及组】T4:跳房子 试题解析
  5. Java 标准 I/O 流编程一览笔录
  6. 防火墙双机热备升级步骤
  7. BT技术原理(BitTorrent)
  8. dubbo之Serialization
  9. java大作业私人管家系统_微软蓝天云平台:中小企业的私人管家
  10. codeforce 379C New Year Ratings Change 题解