/* * LockStore.java 2012-5-15 */ import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 公用的内存锁仓库. 分为获取锁和释放锁两种操作。 * * @version 1.0 */ public final class LockStore { // volatile保证所有线程看到的锁相同 private static volatile Map<String, Date> locks = new HashMap<String, Date>(); private LockStore() { } /** * 根据锁名获取锁 * * @param lockName * 锁名 * @return 是否锁定成功 */ public synchronized static Boolean getLock(String lockName) { Boolean locked = false; if (StringUtils.isEmpty(lockName)) { throw new RuntimeException("Lock name can't be empty"); } Date lockDate = locks.get(lockName); if (lockDate == null) { locks.put(lockName, new Date()); locked = true; } return locked; } /** * 根据锁名释放锁 * * @param lockName * 锁名 */ public synchronized static void releaseLock(String lockName) { if (StringUtils.isEmpty(lockName)) { throw new RuntimeException("Lock name can't be empty"); } Date lockDate = locks.get(lockName); if (lockDate != null) { locks.remove(lockName); } } /** * 获取上次成功锁定的时间 * * @param lockName * 锁名 * @return 如果还没有锁定返回NULL */ public synchronized static Date getLockDate(String lockName) { if (StringUtils.isEmpty(lockName)) { throw new RuntimeException("Lock name can't be empty"); } Date lockDate = locks.get(lockName); return lockDate; } }
锁仓库提供了三个方法,都是静态的,可以在系统内任意地方调用。 这里要提的是锁名,是一个字符串,可以随意构造,通常是需要锁定的方法名+需要单线程处理的标识。比如部门ID。这样不同的部门有不同的锁,独立运行,同一个部门同一个锁,单线程处理。具体使用如下: /* * LockTest.java 2012-6-19 */ import java.text.SimpleDateFormat; import java.util.Date; /** * 锁仓库的使用 * * @version 1.0 */ public class LockTest { public Boolean doSomething(String departmentId, StringBuffer message) { // 同一个部门同时只能有一个处理, 不同部门可以并行处理 String lockName = "doSomething_" + departmentId; Boolean result; if (LockStore.getLock(lockName)) { try { // do things here } finally { LockStore.releaseLock(lockName); result = true; } } else { Date lastLockDate = LockStore.getLockDate(lockName); String messageStr = "您所在的部门已经在处理中, 启动时间为:" + getDateDetailDesc(lastLockDate); message.append(messageStr); result = false; } return result; } /* * 获取日期的具体时间描述 */ private String getDateDetailDesc(Date date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); return sdf.format(date); } } |
通过以上设计,系统内部任何耗时且需要保证单线程的地方都可以用该方法实现非阻塞式的访问,提高用户体验。甚至于有的调用本身就要求这样的设计,只需处理一次,比如做日终。锁名的自定义带来了锁粒度的灵活设定,可以在运行时根据参数实现任意级别的锁定。 |