InterProcessMutex Curator 分布式锁

curator分布式锁,大概过程:
创建临时有序节点,排序,最先创建节点的获取到锁,其他节点监听前一个节点删除事件。当监听到时,则重新进行排序,index最小的获取到锁。


public class lockService {
    @Autowired
    private ZookeeperDao dao;
    InterProcessMutex lock = new InterProcessMutex(new CuratorClient().getClient(),"/lock");

    public  void loclMethod(){

        try {
            //获取锁
            //一直等待锁
            //lock.acquire();
            //尝试获取锁,如果在指定时间获取锁,则返回true
            if (lock.acquire(1000, TimeUnit.SECONDS)){
                int check = dao.check();
                if (check > 0){
                    System.out.println("售出");
                    dao.des(--check);
                }else {
                    System.out.println("没有库存");
                }
            }

            //Thread.sleep(50);
        } catch (Exception e) {
            System.out.println(e);
        }finally {
            try {
                //释放锁
                lock.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}

interProcessMutex.acquire(1000, TimeUnit.SECONDS)

public class InterProcessMutex implements InterProcessLock, Revocable
{
    private final LockInternals internals;
    private final String basePath;

    private final ConcurrentMap threadData = Maps.newConcurrentMap();

    private static class LockData
    {
        final Thread owningThread;
        final String lockPath;
        //分布式锁重入次数
        final AtomicInteger lockCount = new AtomicInteger(1);

        private LockData(Thread owningThread, String lockPath)
        {
            this.owningThread = owningThread;
            this.lockPath = lockPath;
        }
    }

    private static final String LOCK_NAME = "lock-";
    
    @Override
    public void acquire() throws Exception
    {  //获取锁,一直等待
        if ( !internalLock(-1, null) )
        {
            throw new IOException("Lost connection while trying to acquire lock: " + basePath);
        }
    }
    //获取锁,等待指定时间
    @Override
    public boolean acquire(long time, TimeUnit unit) throws Exception
    {
        return internalLock(time, unit);
    }

    private boolean internalLock(long time, TimeUnit unit) throws Exception
    {    //获取当前线程
        Thread currentThread = Thread.currentThread();
        //从ConcurrentMap中获取当前线程的锁数据,不为空,则直接获取锁
        LockData lockData = threadData.get(currentThread);
        if ( lockData != null )
        {    //实现可重入
            // 统计重入次数
            lockData.lockCount.incrementAndGet();
            return true;
        }
        //ConcurrentMap中没有当前线程的所数据,则当前线程尝试去获取锁
        String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
        if ( lockPath != null )
        {  //获取到锁,封装锁数据
            LockData newLockData = new LockData(currentThread, lockPath);
            //保存到ConcurrentMap缓存中
            threadData.put(currentThread, newLockData);
            return true;
        }
        return false;
    }
}

尝试获取锁
String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());

public class LockInternals
{
    String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception
    {
        final long      startMillis = System.currentTimeMillis();
        //无线等待时millisToWait 为null
        final Long      millisToWait = (unit != null) ? unit.toMillis(time) : null;
        //节点数据
        final byte[]    localLockNodeBytes = (revocable.get() != null) ? new byte[0] : lockNodeBytes;
        //当前重试获取锁次数
        int             retryCount = 0;
        // 在Zookeeper中创建的临时顺序节点的路径,相当于一把待激活的分布式锁
        // 激活条件:同级目录子节点,名称排序最小(排队,公平锁)
        String          ourPath = null;
        // 是否已经持有分布式锁
        boolean         hasTheLock = false;
        // 是否已经完成尝试获取分布式锁的操作
        boolean         isDone = false;
        while ( !isDone )
        {    
            isDone = true;
            try
            {  //StandardLockInternalsDriver,创建有序临时节点
                ourPath = driver.createsTheLock(client, path, localLockNodeBytes);
                //是否获取当前锁
                hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);
            }
            catch ( KeeperException.NoNodeException e )
            {
                if ( client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper()) )
                {
                    isDone = false;
                }
                else
                {
                    throw e;
                }
            }
        }
        if ( hasTheLock )
        {  //成功获取锁
            return ourPath;
        }
        return null;
    }
     //是否获取当锁
     private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception
    {  //是否拥有分布式锁
        boolean     haveTheLock = false;
        //是否需要删除子节点
        boolean     doDelete = false;
        try
        {
            if ( revocable.get() != null )
            {
                client.getData().usingWatcher(revocableWatcher).forPath(ourPath);
            }
            //循环尝试获取锁
            while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock )
            {  //排序节点
                List        children = getSortedChildren();
                // 获取前面自己创建的临时顺序子节点的名称
                String              sequenceNodeName = ourPath.substring(basePath.length() + 1);
                // StandardLockInternalsDriver
                //判断是否回去锁,没有获取返回监听路径
                PredicateResults    predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
                if ( predicateResults.getsTheLock() )
                {  //获得锁
                    haveTheLock = true;
                }
                else
                {    //没有所得到锁,监听上一个临时顺序节点
                    String  previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();
                    synchronized(this)
                    {
                        try
                        {    //上一个临时顺序节点如果被删除,会唤醒当前线程继续竞争锁
                            client.getData().usingWatcher(watcher).forPath(previousSequencePath);
                            if ( millisToWait != null )
                            {
                                millisToWait -= (System.currentTimeMillis() - startMillis);
                                startMillis = System.currentTimeMillis();
                                if ( millisToWait <= 0 )
                                {  //获取锁超时,标记删除之前创建的临时顺序节点
                                    doDelete = true;  
                                    break;
                                }
                                wait(millisToWait);
                            }
                            else
                            {
                                wait();
                            }
                        }
                        catch ( KeeperException.NoNodeException e )
                        {
                            // it has been deleted (i.e. lock released). Try to acquire again
                        }
                    }
                }
            }
        }
        catch ( Exception e )
        {
            ThreadUtils.checkInterrupted(e);
            doDelete = true;
            throw e;
        }
        finally
        {
            if ( doDelete )
            {
                deleteOurPath(ourPath);
            }
        }
        return haveTheLock;
    }
    //创建有序临时节点
     @Override
    public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception
    {
        String ourPath;
        if ( lockNodeBytes != null )
        {
            ourPath = client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, lockNodeBytes);
        }
        else
        {
            ourPath = client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
        }
        return ourPath;
    }
}

StandardLockInternalsDriver.getsTheLock(client, children, sequenceNodeName, maxLeases);

public class StandardLockInternalsDriver implements LockInternalsDriver
{
     @Override
    public PredicateResults getsTheLock(CuratorFramework client, List children, String sequenceNodeName, int maxLeases) throws Exception
    {    // 之前创建的临时顺序节点在排序后的子节点列表中的索引
        int             ourIndex = children.indexOf(sequenceNodeName);
         // 校验之前创建的临时顺序节点是否有效
        validateOurIndex(sequenceNodeName, ourIndex);
        //maxLeases 初始化为1
        //ourIndex 为0 表示是当前排序的节点里最先创建出节点的连接,也就是越早创建节点的越早获取到锁
        boolean         getsTheLock = ourIndex < maxLeases;
        //获取到锁则不需要监听,没有获取到锁,则监听前一个节点的删除事件
        String          pathToWatch = getsTheLock ? null : children.get(ourIndex - maxLeases);
         // 返回获取锁的结果,交由上层继续处理(添加监听等操作)
        return new PredicateResults(pathToWatch, getsTheLock);
    }
//校验节点有效性
static void validateOurIndex(String sequenceNodeName, int ourIndex) throws KeeperException
    {
        if ( ourIndex < 0 )
        {     // 由于会话过期或连接丢失等原因,该线程创建的临时顺序节点被Zookeeper服务端删除,往外抛出NoNodeException
            throw new KeeperException.NoNodeException("Sequential path not found: " + sequenceNodeName);
        }
    }
}

释放锁

public class InterProcessMutex implements InterProcessLock, Revocable
{
      @Override
    public void release() throws Exception
    {
        Thread currentThread = Thread.currentThread();
        LockData lockData = threadData.get(currentThread);
        if ( lockData == null )
        {  // 无法从映射表中获取锁信息,不持有锁
            throw new IllegalMonitorStateException("You do not own the lock: " + basePath);
        }

        int newLockCount = lockData.lockCount.decrementAndGet();
        if ( newLockCount > 0 )
        {  // 锁是可重入的,初始值为1,原子-1到0,锁才释放
            return;
        }
        if ( newLockCount < 0 )
        {
            throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + basePath);
        }
        try
        {    //释放锁
            internals.releaseLock(lockData.lockPath);
        }
        finally
        {    //从映射中删除当前线程信息
            threadData.remove(currentThread);
        }
    }
}


public class LockInternals
{
       final void releaseLock(String lockPath) throws Exception
    {    //删除监听
        client.removeWatchers();
        revocable.set(null);
        //删除节点
        deleteOurPath(lockPath);
    }

    private void deleteOurPath(String ourPath) throws Exception
    {
        try
        {    // 后台不断尝试删除
            client.delete().guaranteed().forPath(ourPath);
        }
        catch ( KeeperException.NoNodeException e )
        {
            // ignore - already deleted (possibly expired session, etc.)
        }
    }
}

你可能感兴趣的:(InterProcessMutex Curator 分布式锁)