经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
如何防止秒杀抢购超卖?
来源:cnblogs  作者:林深时见鹿!  时间:2018/11/20 22:53:30  对本文有异议

可以利用redis的事务加上watch监听方法,具体代码如下!

  1. 1 package com.github.distribute.lock.redis;
  2. 2
  3. 3 import java.util.List;
  4. 4 import java.util.Set;
  5. 5 import java.util.concurrent.ExecutorService;
  6. 6 import java.util.concurrent.Executors;
  7. 7
  8. 8 import redis.clients.jedis.Jedis;
  9. 9 import redis.clients.jedis.Transaction;
  10. 10
  11. 11 /**
  12. 12 * redis乐观锁实例
  13. 13 * @author linbingwen
  14. 14 *
  15. 15 */
  16. 16 public class OptimisticLockTest {
  17. 17
  18. 18 public static void main(String[] args) throws InterruptedException {
  19. 19 long starTime=System.currentTimeMillis();
  20. 20
  21. 21 initPrduct();
  22. 22 initClient();
  23. 23 printResult();
  24. 24
  25. 25 long endTime=System.currentTimeMillis();
  26. 26 long Time=endTime-starTime;
  27. 27 System.out.println("程序运行时间: "+Time+"ms");
  28. 28
  29. 29 }
  30. 30
  31. 31 /**
  32. 32 * 输出结果
  33. 33 */
  34. 34 public static void printResult() {
  35. 35 Jedis jedis = RedisUtil.getInstance().getJedis();
  36. 36 Set<String> set = jedis.smembers("clientList");
  37. 37
  38. 38 int i = 1;
  39. 39 for (String value : set) {
  40. 40 System.out.println("第" + i++ + "个抢到商品,"+value + " ");
  41. 41 }
  42. 42
  43. 43 RedisUtil.returnResource(jedis);
  44. 44 }
  45. 45
  46. 46 /*
  47. 47 * 初始化顾客开始抢商品
  48. 48 */
  49. 49 public static void initClient() {
  50. 50 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  51. 51 int clientNum = 10000;// 模拟客户数目
  52. 52 for (int i = 0; i < clientNum; i++) {
  53. 53 cachedThreadPool.execute(new ClientThread(i));
  54. 54 }
  55. 55 cachedThreadPool.shutdown();
  56. 56
  57. 57 while(true){
  58. 58 if(cachedThreadPool.isTerminated()){
  59. 59 System.out.println("所有的线程都结束了!");
  60. 60 break;
  61. 61 }
  62. 62 try {
  63. 63 Thread.sleep(1000);
  64. 64 } catch (InterruptedException e) {
  65. 65 e.printStackTrace();
  66. 66 }
  67. 67 }
  68. 68 }
  69. 69
  70. 70 /**
  71. 71 * 初始化商品个数
  72. 72 */
  73. 73 public static void initPrduct() {
  74. 74 int prdNum = 100;// 商品个数
  75. 75 String key = "prdNum_100001";
  76. 76 String clientList = "clientList";// 抢购到商品的顾客列表
  77. 77 Jedis jedis = RedisUtil.getInstance().getJedis();
  78. 78
  79. 79 if (jedis.exists(key)) {
  80. 80 jedis.del(key);
  81. 81 }
  82. 82
  83. 83 if (jedis.exists(clientList)) {
  84. 84 jedis.del(clientList);
  85. 85 }
  86. 86
  87. 87 jedis.set(key, String.valueOf(prdNum));// 初始化
  88. 88 RedisUtil.returnResource(jedis);
  89. 89 }
  90. 90
  91. 91 }
  92. 92
  93. 93 /**
  94. 94 * 顾客线程
  95. 95 *
  96. 96 * @author linbingwen
  97. 97 *
  98. 98 */
  99. 99 class ClientThread implements Runnable {
  100. 100 Jedis jedis = null;
  101. 101 String key = "prdNum_10001";// 商品主键
  102. 102 String clientList = "clientList";//// 抢购到商品的顾客列表主键
  103. 103 String clientName;
  104. 104
  105. 105 public ClientThread(int num) {
  106. 106 clientName = "编号=" + num;
  107. 107 }
  108. 108
  109. 109 public void run() {
  110. 110 try {
  111. 111 Thread.sleep((int)(Math.random()*5000));// 随机睡眠一下
  112. 112 } catch (InterruptedException e1) {
  113. 113 }
  114. 114 while (true) {
  115. 115 System.out.println("顾客:" + clientName + "开始抢商品");
  116. 116 jedis = RedisUtil.getInstance().getJedis();
  117. 117 try {
  118. 118 jedis.watch(key);
  119. 119 int prdNum = Integer.parseInt(jedis.get(key));// 当前商品个数
  120. 120 if (prdNum > 0) {
  121. 121 Transaction transaction = jedis.multi();
  122. 122 transaction.set(key, String.valueOf(prdNum - 1));
  123. 123 List<Object> result = transaction.exec();
  124. 124 if (result == null || result.isEmpty()) {
  125. 125 System.out.println("悲剧了,顾客:" + clientName + "没有抢到商品");// 可能是watch-key被外部修改,或者是数据操作被驳回
  126. 126 } else {
  127. 127 jedis.sadd(clientList, clientName);// 抢到商品记录一下
  128. 128 System.out.println("好高兴,顾客:" + clientName + "抢到商品");
  129. 129 break;
  130. 130 }
  131. 131 } else {
  132. 132 System.out.println("悲剧了,库存为0,顾客:" + clientName + "没有抢到商品");
  133. 133 break;
  134. 134 }
  135. 135 } catch (Exception e) {
  136. 136 e.printStackTrace();
  137. 137 } finally {
  138. 138 jedis.unwatch();
  139. 139 RedisUtil.returnResource(jedis);
  140. 140 }
  141. 141
  142. 142 }
  143. 143 }
  144. 144
  145. 145 }

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号