|
前面zookeeper系统文章主要讲了zookeeper的实现原理,对我们使用好zookeeper有好处。如何使用zookeeper,让我开始实践之旅。通过简单的实现,zookeeper可以很容易提供分布式锁服务。
互斥锁的实现
在zookeeper的源代码包中recipe下有一个lock实现的例子,大家可以看到一个writelock的实现。writelock相当于一个互斥锁,但要和java提供的lock相比,用起来还是不太一样,需要我们进行一下包装,以下是对writeLock包装后的实现:
public class JoeZKLock implements GlobalLock{
private static final Logger logger = Logger.getLogger(JoeZKLock.class);
final static private String NO_PATH = "no_path";
private WriteLock lock;
final private String lockPath;
final private ReentrantLock jvMLock = new ReentrantLock();
public JoeZKLock(ZooKeeper zk, String lockPath) throws IOException {
this.lockPath = lockPath;
lock = new WriteLock(zk, lockPath, null);
}
public String lock() throws InterruptedException {
jvMLock.lock();
try {
while (true) {
if (lock.lock()) {
return NO_PATH;
}
}
} catch (Throwable e) {
// here need catch Throwable, avoid throw
// runtimeException
// cause the jvmLock unrealsed
logger.error("accquire global lock " + lockPath + " fail.", e);
jvMLock.unlock();
throw new InterruptedException();
}
}
public void unlock(String path) {
try {
lock.unlock();
} finally {
//here ensure release the jvm lock
jvMLock.unlock();
}
}
}
为什么需要在分布式锁的基础上再套一个jvmLock呢?主要原因是如果是同一个jvm的多个线程想要获取锁,如果在本地就互斥,就先在本地排队,这可以避免在zookeeper的锁节点产生大量的孩子,因为在锁实现的代码中需要getChildren,如果孩子越多,性能也越差。
读写锁的实现也大同小异。在此不在一一赘述。
在我们具体的lock server实现中提供了4种锁:
1.互斥锁
2.读写锁
3.path锁
4.id锁
通过这4种锁,完全能满足绝大多数锁的应用场景。 |
|
|