利用zookeeper来实现个分布式锁


前言

10个线程去下单,我们的库存只有5个,如果不加锁就会出现超卖


提示:以下是本篇文章正文内容,下面案例可供参考

准备样例

  1. 商品表,5个库存
    在这里插入图片描述
  2. 再利用nginx做下负载均衡,使请求分配到2个tomcat里去,达到一个分布式效果。

在这里插入图片描述

  1. 准备好zookeeper,安装的方法我之前的博客有,使用也介绍过。

在这里插入图片描述
4. 准备压测工具Jmeter
项目的controller地址
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
启动服务8080和8090
在这里插入图片描述
可以清楚的看到
在这里插入图片描述
只有5个线程能够减库存,其他的都会提示库存不足

关键代码

@Configuration
public class CuratorCfg {

    @Bean(initMethod = "start")
    public CuratorFramework curatorFramework(){
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework client = CuratorFrameworkFactory.newClient("10.20.0.171:2181", retryPolicy);
        return client;
    }

}


```java
@RestController
public class TestController {


    @Autowired
    private OrderService orderService;

    @Value("${server.port}")
    private String port;



    @Autowired
    CuratorFramework curatorFramework;

    @PostMapping("/stock/deduct")
    public Object reduceStock(Integer id) throws Exception {

        //创建互斥锁,传入客户端,和路径
        InterProcessMutex interProcessMutex = new InterProcessMutex(curatorFramework, "/product_" + id);

        try {
            // 阻塞等待,一直等知道加锁成功为止
            interProcessMutex.acquire();
            orderService.reduceStock(id);

        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw e;
            }
        }finally {
            interProcessMutex.release();
        }
        return "ok:" + port;
    }
    
}

原理分析

public InterProcessMutex(CuratorFramework client, String path)
    {
        this(client, path, new StandardLockInternalsDriver());
    }

主要是这个类InterProcessMutex

加锁的主逻辑代码

private boolean internalLock(long time, TimeUnit unit) throws Exception
    {
        /*
           Note on concurrency: a given lockData instance
           can be only acted on by a single thread so locking isn't necessary
        */

        Thread currentThread = Thread.currentThread();

        LockData lockData = threadData.get(currentThread);
        if ( lockData != null )
        {
            // re-entering
            lockData.lockCount.incrementAndGet();
            return true;
        }

        String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
        if ( lockPath != null )
        {
            LockData newLockData = new LockData(currentThread, lockPath);
            threadData.put(currentThread, newLockData);
            return true;
        }

        return false;
    }

这一块主要分为3步:

  1. 把当前线程作为key传进去,拿到lockData
  2. 如果lockPath不等于空,则加锁成功。把加锁对象和当前线程封装起来
  3. 等这个线程再去请求则会发现lockData不为空,直接自增,返回true代表已经拿到锁了。

我们来看这个方法

internals.attemptLock(time, unit, getLockNodeBytes());

在这里插入图片描述
在这里插入图片描述
对于容器节点,如果没有子节点,则会删除掉。
这块就是创建了个类型为容器节点的父节点。子节点是顺序节点

创建好节点之后,要去判断创建的这个节点是不是最小的那个
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
这个方法是拿到所有子节点并进行排序。
然后判断刚刚创建的节点是不是这里面最小的,最小的才能获得锁

zookeeper和redis实现分布式锁的区别

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值