基于zookeeper的分布式锁(三)

转载:http://blog.csdn.net/qq_15370821/article/details/74011036
使用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 locked
client1 released
client2 locked
client2 released

猜你喜欢

转载自blog.csdn.net/u012489091/article/details/79405359