兩種分布式鎖實現方案(一)
阿新 • • 發佈:2018-01-26
如果 pla 並發訪問 可用性 工廠類 mut con comm comment
一。為何使用分布式鎖?
當應用服務器數量超過1臺,對相同數據的訪問可能造成訪問沖突(特別是寫沖突)。單純使用關系數據庫比如MYSQL的應用可以借助於事務來實現鎖,也可以使用版本號等實現樂觀鎖,最大的缺陷就是可用性降低(性能差)。對於GLEASY這種滿足大規模並發訪問請求的應用來說,使用數據庫事務來實現數據庫就有些捉襟見肘了。另外對於一些不依賴數據庫的應用,比如分布式文件系統,為了保證同一文件在大量讀寫操作情況下的正確性,必須引入分布式鎖來約束對同一文件的並發操作。
二。對分布式鎖的要求
1.高性能(分布式鎖不能成為系統的性能瓶頸)
2.避免死鎖(拿到鎖的結點掛掉不會導致其它結點永遠無法繼續)
3.支持鎖重入
三。方案1,基於zookeeper的分布式鎖
[java] view plain copy
- /**
- * DistributedLockUtil.java
- * 分布式鎖工廠類,所有分布式請求都由該工廠類負責
- */
- public class DistributedLockUtil {
- private static Object schemeLock = new Object();
- private static Object mutexLock = new Object();
- private static Map<String, Object> mutexLockMap = new ConcurrentHashMap();
- private String schema;
- private Map<String, DistributedReentrantLock> cache = new ConcurrentHashMap<String, DistributedReentrantLock>();
- private static Map<String, DistributedLockUtil> instances = new ConcurrentHashMap();
- public static DistributedLockUtil getInstance(String schema) {
- DistributedLockUtil u = instances.get(schema);
- if (u == null) {
- synchronized (schemeLock) {
- u = instances.get(schema);
- if (u == null) {
- u = new DistributedLockUtil(schema);
- instances.put(schema, u);
- }
- }
- }
- return u;
- }
- private DistributedLockUtil(String schema) {
- this.schema = schema;
- }
- private Object getMutex(String key) {
- Object mx = mutexLockMap.get(key);
- if (mx == null) {
- synchronized (mutexLock) {
- mx = mutexLockMap.get(key);
- if (mx == null) {
- mx = new Object();
- mutexLockMap.put(key, mx);
- }
- }
- }
- return mx;
- }
- private DistributedReentrantLock getLock(String key) {
- DistributedReentrantLock lock = cache.get(key);
- if (lock == null) {
- synchronized (getMutex(key)) {
- lock = cache.get(key);
- if (lock == null) {
- lock = new DistributedReentrantLock(key, schema);
- cache.put(key, lock);
- }
- }
- }
- return lock;
- }
- public void reset() {
- for (String s : cache.keySet()) {
- getLock(s).unlock();
- }
- }
- /**
- * 嘗試加鎖
- * 如果當前線程已經擁有該鎖的話,直接返回false,表示不用再次加鎖,此時不應該再調用unlock進行解鎖
- *
- * @param key
- * @return
- * @throws InterruptedException
- * @throws KeeperException
- */
- public LockStat lock(String key) throws InterruptedException, KeeperException {
- if (getLock(key).isOwner()) {
- return LockStat.NONEED;
- }
- getLock(key).lock();
- return LockStat.SUCCESS;
- }
- public void clearLock(String key) throws InterruptedException, KeeperException {
- synchronized (getMutex(key)) {
- DistributedReentrantLock l = cache.get(key);
- l.clear();
- cache.remove(key);
- }
- }
- public void unlock(String key, LockStat stat) throws InterruptedException, KeeperException {
- unlock(key, stat, false);
- }
- public void unlock(String key, LockStat stat, boolean keepalive) throws InterruptedException, KeeperException {
- if (stat == null) return;
- if (LockStat.SUCCESS.equals(stat)) {
- DistributedReentrantLock lock = getLock(key);
- boolean hasWaiter = lock.unlock();
- if (!hasWaiter && !keepalive) {
- synchronized (getMutex(key)) {
- lock.clear();
- cache.remove(key);
- }
- }
- }
- }
- public static enum LockStat {
- NONEED,
- SUCCESS
- }
- }
兩種分布式鎖實現方案(一)