01./** 02. * @author http://blog.csdn.net/java2000_wl 03. * @version <b>1.0.0</b> 04. */ 05.public class RedisBillLockHandler implements IBatchBillLockHandler { 06. 07. private static final Logger LOGGER = LoggerFactory.getLogger(RedisBillLockHandler.class); 08. 09. private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3; 10. 11. private static final int DEFAULT_BATCH_EXPIRE_TIME = 6; 12. 13. private final JedisPool jedisPool; 14. 15. /** 16. * 构造 17. * @author http://blog.csdn.net/java2000_wl 18. */ 19. public RedisBillLockHandler(JedisPool jedisPool) { 20. this.jedisPool = jedisPool; 21. } 22. 23. /** 24. * 获取锁 如果锁可用 立即返回true, 否则返回false 25. * @author http://blog.csdn.net/java2000_wl 26. * @param billIdentify 27. * @return 28. */ 29. public boolean tryLock(IBillIdentify billIdentify) { 30. return tryLock(billIdentify, 0L, null); 31. } 32. 33. /** 34. * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false 35. * @author http://blog.csdn.net/java2000_wl 36. * @param billIdentify 37. * @param timeout 38. * @param unit 39. * @return 40. */ 41. public boolean tryLock(IBillIdentify billIdentify, long timeout, TimeUnit unit) { 42. String key = (String) billIdentify.uniqueIdentify(); 43. Jedis jedis = null; 44. try { 45. jedis = getResource(); 46. long nano = System.nanoTime(); 47. do { 48. LOGGER.debug("try lock key: " + key); 49. Long i = jedis.setnx(key, key); 50. if (i == 1) { 51. jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME); 52. LOGGER.debug("get lock, key: " + key + " , expire in " + DEFAULT_SINGLE_EXPIRE_TIME + " seconds."); 53. return Boolean.TRUE; 54. } else { // 存在锁 55. if (LOGGER.isDebugEnabled()) { 56. String desc = jedis.get(key); 57. LOGGER.debug("key: " + key + " locked by another business:" + desc); 58. } 59. } 60. if (timeout == 0) { 61. break; 62. } 63. Thread.sleep(300); 64. } while ((System.nanoTime() - nano) < unit.toNanos(timeout)); 65. return Boolean.FALSE; 66. } catch (JedisConnectionException je) { 67. LOGGER.error(je.getMessage(), je); 68. returnBrokenResource(jedis); 69. } catch (Exception e) { 70. LOGGER.error(e.getMessage(), e); 71. } finally { 72. returnResource(jedis); 73. } 74. return Boolean.FALSE; 75. } 76. 77. /** 78. * 如果锁空闲立即返回 获取失败 一直等待 79. * @author http://blog.csdn.net/java2000_wl 80. * @param billIdentify 81. */ 82. public void lock(IBillIdentify billIdentify) { 83. String key = (String) billIdentify.uniqueIdentify(); 84. Jedis jedis = null; 85. try { 86. jedis = getResource(); 87. do { 88. LOGGER.debug("lock key: " + key); 89. Long i = jedis.setnx(key, key); 90. if (i == 1) { 91. jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME); 92. LOGGER.debug("get lock, key: " + key + " , expire in " + DEFAULT_SINGLE_EXPIRE_TIME + " seconds."); 93. return; 94. } else { 95. if (LOGGER.isDebugEnabled()) { 96. String desc = jedis.get(key); 97. LOGGER.debug("key: " + key + " locked by another business:" + desc); 98. } 99. } 100. Thread.sleep(300); 101. } while (true); 102. } catch (JedisConnectionException je) { 103. LOGGER.error(je.getMessage(), je); 104. returnBrokenResource(jedis); 105. } catch (Exception e) { 106. LOGGER.error(e.getMessage(), e); 107. } finally { 108. returnResource(jedis); 109. } 110. } 111. 112. /** 113. * 释放锁 114. * @author http://blog.csdn.net/java2000_wl 115. * @param billIdentify 116. */ 117. public void unLock(IBillIdentify billIdentify) { 118. List<IBillIdentify> list = new ArrayList<IBillIdentify>(); 119. list.add(billIdentify); 120. unLock(list); 121. } 122. 123. /** 124. * 批量获取锁 如果全部获取 立即返回true, 部分获取失败 返回false 125. * @author http://blog.csdn.net/java2000_wl 126. * @date 2013-7-22 下午10:27:44 127. * @param billIdentifyList 128. * @return 129. */ 130. public boolean tryLock(List<IBillIdentify> billIdentifyList) { 131. return tryLock(billIdentifyList, 0L, null); 132. } 133. 134. /** 135. * 锁在给定的等待时间内空闲,则获取锁成功 返回true, 否则返回false 136. * @author http://blog.csdn.net/java2000_wl 137. * @param billIdentifyList 138. * @param timeout 139. * @param unit 140. * @return 141. */ 142. public boolean tryLock(List<IBillIdentify> billIdentifyList, long timeout, TimeUnit unit) { 143. Jedis jedis = null; 144. try { 145. List<String> needLocking = new CopyOnWriteArrayList<String>(); 146. List<String> locked = new CopyOnWriteArrayList<String>(); 147. jedis = getResource(); 148. long nano = System.nanoTime(); 149. do { 150. // 构建pipeline,批量提交 151. Pipeline pipeline = jedis.pipelined(); 152. for (IBillIdentify identify : billIdentifyList) { 153. String key = (String) identify.uniqueIdentify(); 154. needLocking.add(key); 155. pipeline.setnx(key, key); 156. } 157. LOGGER.debug("try lock keys: " + needLocking); 158. // 提交redis执行计数 159. List<Object> results = pipeline.syncAndReturnAll(); 160. for (int i = 0; i < results.size(); ++i) { 161. Long result = (Long) results.get(i); 162. String key = needLocking.get(i); 163. if (result == 1) { // setnx成功,获得锁 164. jedis.expire(key, DEFAULT_BATCH_EXPIRE_TIME); 165. locked.add(key); 166. } 167. } 168. needLocking.removeAll(locked); // 已锁定资源去除 169. 170. if (CollectionUtils.isEmpty(needLocking)) { 171. return true; 172. } else { 173. // 部分资源未能锁住 174. LOGGER.debug("keys: " + needLocking + " locked by another business:"); 175. } 176. 177. if (timeout == 0) { 178. break; 179. } 180. Thread.sleep(500); 181. } while ((System.nanoTime() - nano) < unit.toNanos(timeout)); 182. 183. // 得不到锁,释放锁定的部分对象,并返回失败 184. if (!CollectionUtils.isEmpty(locked)) { 185. jedis.del(locked.toArray(new String[0])); 186. } 187. return false; 188. } catch (JedisConnectionException je) { 189. LOGGER.error(je.getMessage(), je); 190. returnBrokenResource(jedis); 191. } catch (Exception e) { 192. LOGGER.error(e.getMessage(), e); 193. } finally { 194. returnResource(jedis); 195. } 196. return true; 197. } 198. 199. /** 200. * 批量释放锁 201. * @author http://blog.csdn.net/java2000_wl 202. * @param billIdentifyList 203. */ 204. public void unLock(List<IBillIdentify> billIdentifyList) { 205. List<String> keys = new CopyOnWriteArrayList<String>(); 206. for (IBillIdentify identify : billIdentifyList) { 207. String key = (String) identify.uniqueIdentify(); 208. keys.add(key); 209. } 210. Jedis jedis = null; 211. try { 212. jedis = getResource(); 213. jedis.del(keys.toArray(new String[0])); 214. LOGGER.debug("release lock, keys :" + keys); 215. } catch (JedisConnectionException je) { 216. LOGGER.error(je.getMessage(), je); 217. returnBrokenResource(jedis); 218. } catch (Exception e) { 219. LOGGER.error(e.getMessage(), e); 220. } finally { 221. returnResource(jedis); 222. } 223. } 224. 225. /** 226. * @author http://blog.csdn.net/java2000_wl 227. * @date 2013-7-22 下午9:33:45 228. * @return 229. */ 230. private Jedis getResource() { 231. return jedisPool.getResource(); 232. } 233. 234. /** 235. * 销毁连接 236. * @author http://blog.csdn.net/java2000_wl 237. * @param jedis 238. */ 239. private void returnBrokenResource(Jedis jedis) { 240. if (jedis == null) { 241. return; 242. } 243. try { 244. //容错 245. jedisPool.returnBrokenResource(jedis); 246. } catch (Exception e) { 247. LOGGER.error(e.getMessage(), e); 248. } 249. } 250. 251. /** 252. * @author http://blog.csdn.net/java2000_wl 253. * @param jedis 254. */ 255. private void returnResource(Jedis jedis) { 256. if (jedis == null) { 257. return; 258. } 259. try { 260. jedisPool.returnResource(jedis); 261. } catch (Exception e) { 262. LOGGER.error(e.getMessage(), e); 263. } 264. }