一。为何使用分布式锁?
当应用服务器数量超过1台,对相同数据的访问可能造成访问冲突(特别是写冲突)。单纯使用关系数据库比如MYSQL的应用可以借助于事务来实现锁,也可以使用版本号等实现乐观锁,最大的缺陷就是可用性降低(性能差)。对于GLEASY这种满足大规模并发访问请求的应用来说,使用数据库事务来实现数据库就有些捉襟见肘了。另外对于一些不依赖数据库的应用,比如分布式文件系统,为了保证同一文件在大量读写操作情况下的正确性,必须引入分布式锁来约束对同一文件的并发操作。
二。对分布式锁的要求
1.高性能(分布式锁不能成为系统的性能瓶颈)
2.避免死锁(拿到锁的结点挂掉不会导致其它结点永远无法继续)
3.支持锁重入
三。方案1,基于zookeeper的分布式锁
- /**
- * 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
- }
- }