/* * 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); } } |
通過以上設計,系統內部任何耗時且需要保證單線程的地方都可以用該方法實現非阻塞式的訪問,提高用戶體驗。甚至于有的調用本身就要求這樣的設計,只需處理一次,比如做日終。鎖名的自定義帶來了鎖粒度的靈活設定,可以在運行時根據參數實現任意級別的鎖定。 |