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. }