基于zookeeper+curator的分布式锁代码实现

  • zookeeper的配置和安装请移步zookeeper的安装
  • 分布式锁的可选择性一般常用的为redis的分布式锁和zookeeper的分布式锁,redis是以一个key值作为唯一,zookeeper是以创建的临时节点下的子节点来创建一个唯一,redis分布式锁请移步基于redisson的分布式锁
  • 下面是具体的代码实现
  • 依赖
<dependency>
    <groupId>org.apache.curator</groupId>
       <artifactId>curator-recipes</artifactId>
    <version>2.7.0</version>
</dependency>

<dependency>
    <groupId>com.gitee.reger</groupId>
      <artifactId>spring-boot-starter-dubbo</artifactId>
    <version>1.0.9</version>
</dependency>
  • 代码配置
server.port=8081
#服务治理当前项目的名称
spring.dubbo.application.name=servermodule
#暴露服务的包路径
spring.dubbo.base-package=com.sunyw.xyz.service
#zookeeper的注册地址
spring.dubbo.registry.address=127.0.0.1
#zookeeper的端口
spring.dubbo.registry.port=2181
#性能调优,balabala.....
spring.dubbo.protocol.name=dubbo
#重试次数,默认为2,这里设置为0
spring.dubbo.provider.retries=0
#超时时间
spring.dubbo.consumer.timeout=40000
spring.dubbo.registry.timeout=40000
spring.dubbo.provider.timeout=40000
#配置实际地址,只是多地址配置示范规则为 ip1:port1, ip2:port2.....
zookeeper.address=127.0.0.1:2181,127.0.0.1:2181,127.0.0.1:2181

  • 配置类主要配置了curator,curator是一个zookeeper的操作框架,官网地址curator
package com.sunyw.xyz.service.version.config;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.api.CuratorEventType;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.WatchedEvent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ZkServerConfig {

   @Value("${zookeeper.address}")
    private String zkAddress;

    @Bean
    public CuratorFramework initCurator() {
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(zkAddress, retry);
        curatorFramework.getCuratorListenable().addListener(new ZkListener() {
        });
        curatorFramework.start();
        return curatorFramework;

    }

    /**
     * 监听
     */
    public class ZkListener implements CuratorListener {

        @Override
        public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception {
            CuratorEventType eventType = event.getType();
            if (eventType == CuratorEventType.WATCHED) {
                WatchedEvent eventWatchedEvent = event.getWatchedEvent();
                String eventPath = eventWatchedEvent.getPath();
                if (null != eventPath) {
                    client.checkExists().watched().forPath(eventPath);
                }
            }
        }
    }
}

  • 业务代码,模拟减库存,没有使用到数据库,大概可以看一下
package com.sunyw.xyz.service.version.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class ZkLockController {

    @Autowired
    private CuratorFramework curatorFramework;
    /**
     * 临时节点名称
     */
    private static final String LOCK_NAME = "/lock";

    /**
     * 库存
     */
    private int kz = 5;

    /**
     * zookeeper分布式锁使用demo
     * @param id
     * @return
     */
    @GetMapping("/add/{id}")
    public String add(@PathVariable String id) {

        String name = Thread.currentThread().getName();
        log.info("线程{}->开始进入add方法", name);
        InterProcessSemaphoreMutex mutex = new InterProcessSemaphoreMutex(curatorFramework, LOCK_NAME);
        log.info("线程{}->开始获取🔒", name);
        boolean acquire;
        try {
            acquire = mutex.acquire(6000, TimeUnit.SECONDS);
            if (acquire) {
                log.info("线程{}->获取🔒成功开始进行购买,剩余数量{}", name, kz);
                if (kz == 0) {
                    log.info("销售一空了~~~~~~~~~~~~~~~~~~~~~~~~");
                    return "销售一空";
                }
                kz--;
                Thread.sleep(1000);
                log.info("线程{}->购买完毕", name);
            }
        } catch (Exception e) {
            log.error("业务执行错误信息-->", e);
        } finally {
            log.info("线程{}->开始释放🔒", name);
            try {
                mutex.release();
                log.info("线程{}->释放🔒成功", name);
            } catch (Exception e) {
                log.error("释放🔒错误信息-->", e);
            }
        }
        return "SUCCESS";
    }

}

  • 执行结果
    在这里插入图片描述
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值