zookeeper—分布式锁实现(笔记)

来源:互联网 发布:比特币交易网免费源码 编辑:程序博客网 时间:2024/06/04 18:59

使用Curator客户端实现

1.当有客户端访问锁资源时,先在zookeeper服务器上创建的锁节点下创建一个顺序节点,使用完锁资源删除创建的顺序节点。

2.当一个新的客户端想要访问锁资源时,先去zookeeper服务器锁节点下创建一个新节点,判断当前创建的节点编号是否为最小,若为最小表示当前只有本客户端想访问锁资源,然后访问资源便是。

3.若当前创建的节点编号不为最小,表示之前已有客户端在访问锁资源,需排队等待。所以监听比当前节点编号小一号的节点,若前一个节点被删除表示排在当前客户端前面的都执行完了锁资源,可以开始访问锁资源。

客户端操作接口:

public interface DistributedLock {    //获取锁,若没有得到就等待    public void acquire() throws Exception;    //获取锁,直到超时    public boolean acquire(long time,TimeUnit unit) throws Exception;    //释放锁    public void realease() throws Exception;}

基础类(对zookeeper服务器操作的详细实现):

public class BaseDistributedLock  {    private final CuratorFramework client;    private final String path;    protected  final String basePath;    private final String lockName;    private final static Integer MAX_RETRY_COUNT = 10;    public BaseDistributedLock(CuratorFramework client, String path, String lockName) {        this.client = client;        this.basePath = path;        this.path = path.concat("/").concat(lockName);        this.lockName = lockName;    }    private void deleteOurpath(String ourPath) throws Exception {        client.delete().guaranteed().deletingChildrenIfNeeded().forPath(ourPath);    }    private String createLockNode(CuratorFramework client, String path) throws Exception  {        return client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, null);    }    private boolean waitToLock(long startMillis, Long millisToWait, String ourPath) throws Exception {        boolean haveTheLock = false;        boolean doDelete = false;        try {            while (!haveTheLock){                List<String> children = getSortedChildren();                String sequenceNodeName = ourPath.substring(basePath.length() + 1);                int ourIndex = children.indexOf(sequenceNodeName);                if(ourIndex <0) {                    throw new NoNodeException("节点不存在: " + sequenceNodeName);                }                boolean isGetTheLock = ourIndex == 0;                String psthToWatch = isGetTheLock ? null : children.get(ourIndex - 1);                if(isGetTheLock) {                    haveTheLock = true;                }else {                    String previousSequencePath = basePath.concat("/").concat(psthToWatch);                    final CountDownLatch latch = new CountDownLatch(1);                    try {                        client.getData().usingWatcher(new Watcher() {                            @Override                            public void process(WatchedEvent event) {                                if(event.getType() == EventType.NodeDeleted) {                                    latch.countDown();                                }                            }                        }                        ).forPath(previousSequencePath);                        if(millisToWait != null) {                            millisToWait -= (System.currentTimeMillis() - startMillis);                            startMillis = System.currentTimeMillis();                            if(millisToWait <= 0) {                                doDelete = true;                                break;                            }                            latch.await(millisToWait, TimeUnit.MICROSECONDS);                        }else {                            latch.await();                        }                    }catch(NoNodeException e) {                        e.printStackTrace();                    }                }            }        }catch(Exception e ) {            doDelete = true;        }finally{            if(doDelete) {                deleteOurpath(ourPath);            }        }        return haveTheLock;    }    private String getLockNodeNumber(String str, String lockName ) {        int index = str.lastIndexOf(lockName);        if(index >= 0) {            index += lockName.length();            return index <= str.length() ? str.substring(index) : "";        }        return str;    }    public List<String> getSortedChildren() throws Exception{        try {            List<String> children = client.getChildren().forPath(basePath);            Collections.sort            (                children,                new Comparator<String>()                {                    public int compare(String lhs, String rhs)                    {                        return getLockNodeNumber(lhs, lockName).compareTo(getLockNodeNumber(rhs, lockName));                    }                }            );            return children;        }catch(NoNodeException e){            client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(basePath);            return getSortedChildren();        }    }    protected void releaseLock(String lockPath) throws Exception {        deleteOurpath(lockPath);    }    protected String attemptLock(long time, TimeUnit unit) throws Exception {        final long startMillis = System.currentTimeMillis();        final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;        String ourPath = null;        boolean hasTheLock = false;        boolean isDone = false;        int retryCount = 0;        while(!isDone) {            isDone = true;            try{                ourPath = createLockNode(client, path);                hasTheLock = waitToLock(startMillis, millisToWait, ourPath);                }catch(NoNodeException e) {                if(retryCount++ < MAX_RETRY_COUNT) {                    isDone = false;                }else {                    throw e;                }            }        }        if(hasTheLock) {            return ourPath;        }         return null;    }}

客户端的具体实现类:

public class SimpleDistributedLock extends BaseDistributedLock implements DistributedLock {    //锁名称前缀    private static final String LOCK_NAME = "lock-";    private String ourLockPath;    public SimpleDistributedLock(CuratorFramework client, String path) {        super(client, path, LOCK_NAME);    }    private boolean internalLock(long time, TimeUnit unit) throws Exception{        ourLockPath = attemptLock(time, unit);        return ourLockPath != null;    }    @Override    public void acquire() throws Exception {        if(!internalLock(-1,null)) {            throw new IOException("连接丢失!" + basePath + "路径不能获取锁");        }    }    @Override    public boolean acquire(long time, TimeUnit unit) throws Exception {        return internalLock(time, unit);    }    @Override    public void realease() throws Exception {        releaseLock(ourLockPath);    }}

测试类:

public static void main(String[] args) {        RetryPolicy retry = new ExponentialBackoffRetry(1000, 3);        CuratorFramework client1 = CuratorFrameworkFactory.newClient("192.168.0.3:2181", 5000, 5000, retry);        CuratorFramework client2 = CuratorFrameworkFactory.newClient("192.168.0.3:2181", 5000, 5000, retry);        client1.start();        client2.start();        SimpleDistributedLock lock1 = new SimpleDistributedLock(client1, "/Lock");        SimpleDistributedLock lock2 = new SimpleDistributedLock(client1, "/Lock");        try {            lock1.acquire();            System.out.println("Client1 locked");            Thread client2Thr = new Thread(new Runnable() {                @Override                public void run() {                    try {                        lock2.acquire();                        System.out.println("client2 locked");                        lock2.realease();                        System.out.println("client2 released");                    }catch(Exception e) {                        e.printStackTrace();                    }                 }            });            client2Thr.start();            Thread.sleep(5000);            lock1.realease();            System.out.println("client1 released");            client2Thr.join();        }catch(Exception e) {            e.printStackTrace();        }    }

console:

Client1 lockedclient1 releasedclient2 lockedclient2 released
原创粉丝点击