多线程程序的锁定已经有良好的支持,通常使用synchronized修饰一个方法或者一段代码。但是有一个问题,多个线程同时调用同一个方法的时候,所

有线程都被排队处理了。该被调用的方法越耗时,线程越多的时候,等待的线程等待的时间也就越长,甚至于几分钟或者几十分钟。对于Web等对反应时间要求很

高的系统来说,这是不可以接受的。本文就介绍一种自己实现的锁定方法,可以在没有拿到锁之后马上返回,告诉客户稍候重试。51Testing软件测试网"oq+O+]dQS

某一段程序同一时刻需要保证只能单线程调用,那么策略很简单,最先到的线程获取锁成功,在它释放之前其它线程都会获取失败。首先要构造一个全局的系统锁仓库,代码如下:X\Ik(?'d(~051Testing软件测试网5@tN/@,cb-r6Z:k

/*
c%sG{d0 * LockStore.java  2012-5-15
C:nwY w!J0 */51Testing软件测试网h1Ci%{)rb%?Z{
9ATheG,iV"Jt0import java.util.Date;
v8z}7@2x0import java.util.HashMap;51Testing软件测试网 S2S/l#|qK H
import java.util.Map;51Testing软件测试网M3`t)r/N.N+?~Q51Testing软件测试网$L;E"^\J2] t:l-?
/**
:t|EyRo0 * 公用的内存锁仓库. 分为获取锁和释放锁两种操作。
lLVx:E0 *51Testing软件测试网ELkG-T X~
* @version 1.0
\MaBo'R0 */51Testing软件测试网 f y$\in/x*n
public final class LockStore {51Testing软件测试网o@+Ta0Y3Yo
// volatile保证所有线程看到的锁相同
s
W;~C+}0 private static volatile Map locks = new HashMap();-O#Bj;qA.hL2sz051Testing软件测试网'd$va#^6@9B1\8};q
private LockStore() {,BFDz/l#{*K%t6k051Testing软件测试网OXT}A)Z _
}\LW3M)\$q\b0
B'|U6Y#Umv0/**
&B'`V3o5cc_$I-E0  * 根据锁名获取锁51Testing软件测试网)hsIz+G
*
K q2CR_0  * @param lockName
O3o0w;Ip6a Q*_#n~0  *            锁名51Testing软件测试网,|-}4Q!E/O6vH(x
* @return 是否锁定成功51Testing软件测试网't0L7m&EYhZ1p
*/
^5|s1hv?0 public synchronized static Boolean getLock(String lockName) {
C#^4h7{"O7T(m&R!hn^0  Boolean locked = false;\'[7\({$iO3K0
7QM)J6W4g*WO6N%`0if (StringUtils.isEmpty(lockName)) {
p
f-J5n\o~i0   throw new RuntimeException("Lock name can't be empty");
*G&D(p;AQe.R0  }w&XW"Mjd,\051Testing软件测试网Ka@#Ry:]
Date lockDate = locks.get(lockName);51Testing软件测试网|
n{? M{u9Gh
if (lockDate == null) {
2ouv|f0   locks.put(lockName, new Date());51Testing软件测试网!RQ1C$v8W
locked = true;
3n.o"zU
A0  }51Testing软件测试网b~)G"S8?3z5Pc&}
#m6xK/f"Z:J&E)|,Eb0return locked;
0BP;~pMP2McI0 }h;HWU[DK-L051Testing软件测试网&l/?vE9~.D%Xn)|
/**
([C
z\ jg0  * 根据锁名释放锁
naw"{,A |0  *
)~!{r5OHj)`!t0  * @param lockName
Q)i-OI9BO)Q,D[yk0  *            锁名51Testing软件测试网jwZ3]qs
*/51Testing软件测试网&Igqsh7u]+T
public synchronized static void releaseLock(String lockName) {51Testing软件测试网dvz6li+N
if (StringUtils.isEmpty(lockName)) {51Testing软件测试网?:^m#~V~b!j
throw new RuntimeException("Lock name can't be empty");
og(lB [d5V,`pj0  }%x&q~C;T(K}0
/Kr"Xj x#}@0Date lockDate = locks.get(lockName);51Testing软件测试网9g$pQ0NFdU1K
if (lockDate != null) {
N7\gWo7Rjr)[ z0   locks.remove(lockName);51Testing软件测试网`#eI{1eJ1Y Ob
}51Testing软件测试网6N*gZ${|!B
}51Testing软件测试网H,{4v)@5~d
;M
Z[XU*L0/**
e6dqs']#AFr1]:A0  * 获取上次成功锁定的时间51Testing软件测试网t6p$Nl,vo"@n!Gz
*51Testing软件测试网jbE5A[s3cl6L9@
* @param lockName
a_(RS,ll;Z
}%m,[0  *            锁名
&t2f%cN'Y;f5p4Ao)Sw0  * @return 如果还没有锁定返回NULL
+^?MW3Vb0  */
%IJZ3_$gE\6p0 public synchronized static Date getLockDate(String lockName) {51Testing软件测试网7_9V/o(vEH
if (StringUtils.isEmpty(lockName)) {51Testing软件测试网;zJ4Y@&H2f;q ^0M
throw new RuntimeException("Lock name can't be empty");
uaq3|1l-L'tihQ0  }51Testing软件测试网V rs1Bh\9h`6d{
j7k
x;m3ocGg1S y}a#?uo0Date lockDate = locks.get(lockName);51Testing软件测试网3u5K6e \;U+X;h51Testing软件测试网!r6W"p.kI%T[8Q:]X1D
return lockDate;
3L;a!Hf(me0 }
kTo$k'm&J4a3z$UU.]0}51Testing软件测试网9BybL!{}3b51Testing软件测试网(`3S!@n&r

锁仓库提供了三个方法,都是静态的,可以在系统内任意地方调用。 这里要提的是锁名,是一个字符串,可以随意构造,通常是需要锁定的方法名+需要单线程处理的标识。比如部门ID。这样不同的部门有不同的锁,独立运行,同一个部门同一个锁,单线程处理。具体使用如下:t

N\zkIA0
v5o!mY7q {9_5}09u2D1F@`cRW!I0ElQP}Q0/*51Testing软件测试网e%kN$FLt@.[z
* LockTest.java  2012-6-1951Testing软件测试网K9Zk*IgZ8dT
*/:yW spi;R0Icf!c051Testing软件测试网7KG MZw,X
import java.text.SimpleDateFormat;
n~X&Y.x