SequenceLockHelper.java 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package cn.com.qmth.examcloud.web.helpers;
  2. import java.util.List;
  3. import java.util.concurrent.TimeUnit;
  4. import org.apache.commons.lang.StringUtils;
  5. import org.assertj.core.util.Arrays;
  6. import com.google.common.collect.Lists;
  7. import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
  8. import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
  9. import cn.com.qmth.examcloud.commons.util.ThreadLocalUtil;
  10. import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
  11. import cn.com.qmth.examcloud.web.exception.SequenceLockException;
  12. import cn.com.qmth.examcloud.web.interceptor.SeqlockInterceptor;
  13. import cn.com.qmth.examcloud.web.redis.RedisClient;
  14. import cn.com.qmth.examcloud.web.support.ServletUtil;
  15. import cn.com.qmth.examcloud.web.support.SpringContextHolder;
  16. /**
  17. * 并发顺序锁
  18. *
  19. * @author WANGWEI
  20. * @date 2019年2月22日
  21. * @Copyright (c) 2018-2020 WANGWEI [QQ:522080330] All Rights Reserved.
  22. */
  23. public class SequenceLockHelper {
  24. private static final ExamCloudLog LOG = ExamCloudLogFactory.getLog(SequenceLockHelper.class);
  25. private static final String LOCK_PREFIX = "$_LOCK_C:";
  26. private static RedisClient redisClient;
  27. private static RedisClient getRedisClient() {
  28. if (null == redisClient) {
  29. redisClient = SpringContextHolder.getBean(RedisClient.class);
  30. }
  31. return redisClient;
  32. }
  33. /**
  34. * 获取顺序请求锁<br>
  35. *
  36. * @param args
  37. * @throws SequenceLockException
  38. * 获取锁失败时抛出异常
  39. */
  40. public static void getLock(Object... args) throws SequenceLockException {
  41. String key = LOCK_PREFIX + StringUtils.join(Arrays.asList(args), "_");
  42. int timeout = 60 * 2;
  43. if (getRedisClient().setIfAbsent(key, ThreadLocalUtil.getTraceId(), timeout)) {
  44. if (LOG.isDebugEnabled()) {
  45. LOG.debug("locked");
  46. }
  47. @SuppressWarnings("unchecked")
  48. List<String> keyList = (List<String>) ServletUtil.getRequest()
  49. .getAttribute(HttpServletRequestAttribute.$_CUSTOM_SEQUENCE_LOCK.name());
  50. if (null == keyList) {
  51. keyList = Lists.newArrayList();
  52. }
  53. keyList.add(key);
  54. ServletUtil.getRequest().setAttribute(
  55. HttpServletRequestAttribute.$_CUSTOM_SEQUENCE_LOCK.name(), keyList);
  56. } else {
  57. Long expire = getRedisClient().getExpire(key, TimeUnit.SECONDS);
  58. if (null == expire || expire > timeout) {
  59. getRedisClient().delete(key);
  60. }
  61. throw new SequenceLockException("请求等待,请稍后重试!");
  62. }
  63. }
  64. /**
  65. * 释放锁<br>
  66. * 接口调用不要调用此方法释放锁,此锁会在拦截器<{@link SeqlockInterceptor}中释放.
  67. *
  68. * @author WANGWEI
  69. * @param args
  70. */
  71. public static void releaseLock(Object... args) {
  72. String key = LOCK_PREFIX + StringUtils.join(Arrays.asList(args), "_");
  73. getRedisClient().expire((String) key, 100, TimeUnit.MILLISECONDS);
  74. @SuppressWarnings("unchecked")
  75. List<String> keyList = (List<String>) ServletUtil.getRequest()
  76. .getAttribute(HttpServletRequestAttribute.$_CUSTOM_SEQUENCE_LOCK.name());
  77. if (null != keyList) {
  78. if (keyList.contains(key)) {
  79. keyList.remove(key);
  80. }
  81. }
  82. }
  83. /**
  84. * 获取顺序请求锁<br>
  85. *
  86. * @param args
  87. * @throws SequenceLockException
  88. * 获取锁失败时抛出异常
  89. */
  90. public static void getLockSimple(Object... args) throws SequenceLockException {
  91. String key = LOCK_PREFIX + StringUtils.join(Arrays.asList(args), "_");
  92. int timeout = 60 * 2;
  93. if (!getRedisClient().setIfAbsent(key, ThreadLocalUtil.getTraceId(), timeout)) {
  94. Long expire = getRedisClient().getExpire(key, TimeUnit.SECONDS);
  95. if (null == expire || expire > timeout) {
  96. getRedisClient().delete(key);
  97. }
  98. throw new SequenceLockException("请求等待,请稍后重试!");
  99. }
  100. }
  101. /**
  102. * 释放锁<br>
  103. * 接口调用不要调用此方法释放锁,此锁会在拦截器<{@link SeqlockInterceptor}中释放.
  104. *
  105. * @author WANGWEI
  106. * @param args
  107. */
  108. public static void releaseLockSimple(Object... args) {
  109. String key = LOCK_PREFIX + StringUtils.join(Arrays.asList(args), "_");
  110. getRedisClient().delete(key);
  111. }
  112. }