開始的時候項目沒有添加互斥鎖,用的依然是老的思路,在并發量增加的情況下,遇到了很多的問題,包括數據庫重復讀等,想了下考慮增加 互斥鎖來排序對單個資源的操作。
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Order(1) public @interface DistributeLock {LockType type() default LockType.Id;enum LockType {Id,Function;} }
? 實現了兩個方式,用注解+Aspect的方式 和 try(Closeable){} 的方式確保鎖的釋放。
? 實現依托于redis的?
String result = conn.set(key, value, "NX", "PX", expire);
方法,該方法在單節點和集群下都可用。我測試用的單節點生產cluster集群都測試通過。
public class MutexLock implements Closeable {RedisCache redisCache;// private boolean isWorkFine = false;private String key;private final String DEFAULT_PREFIX = "DEFAULT";public boolean isWorkFine() {return isWorkFine;}public MutexLock(String prefix, Long id) throws EirException{redisCache = ApplicationContextHelper.getBean(RedisCache.class);if (redisCache == null) {System.out.println("枷鎖 redis 未開啟");return;}this.key = (StringUtil.isNullOrEmpty(prefix) ? DEFAULT_PREFIX : prefix) + ":" + id;Boolean tryGetLock = new RedisUtils(redisCache).setnx(key);if (tryGetLock != null && tryGetLock) {isWorkFine = true;}if (tryGetLock != null && !tryGetLock) {throw new EirException("當前資源正忙");}}/*** Closes this stream and releases any system resources associated* with it. If the stream is already closed then invoking this* method has no effect.* <p>* <p> As noted in {@link AutoCloseable#close()}, cases where the* close may fail require careful attention. It is strongly advised* to relinquish the underlying resources and to internally* <em>mark</em> the {@code Closeable} as closed, prior to throwing* the {@code IOException}.** @throws IOException if an I/O error occurs*/@Overridepublic void close() {try {if (isWorkFine) {new RedisUtils(redisCache).releaseLock(this.key);}} catch (Exception e) {e.printStackTrace();}}
?
redisUtils 中在getLock的時候 設置了等待時間,5秒鐘,超過之后會返回“資源正忙”, 鎖也加了超時時間, 避免死鎖問題。
測試代碼就不貼了。
總結下來這個應該是最廉價實惠的互斥鎖方案了。