zookeeper实现分布式锁(springboot整合)

1、安装zookeeper

参考:https://blog.csdn.net/qq_33612228/article/details/106424541

2、实现思路

1、创建有序临时节点

2、触发“尝试取锁逻辑”,如果自己是临时锁节点序列的第一个,则取得锁,获取锁成功。

3、如果自己不是序列中第一个,则监听前一个锁节点变更。同时阻塞线程。

4、当前一个锁节点变更时,通过watcher恢复线程,然后再次到步骤2“尝试取锁逻辑”
在这里插入图片描述

3、springboot集成实现

3.1、pom引入

 <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
 </dependency>

3.2、代码实例

分布式锁工具类

public class ZookeeperLock{

	//zk的连接串
	String IP = "127.0.0.1:2181";
	//计数器对象
	CountDownLatch countDownLatch = new CountDownLatch(1);

	//zk配置信息
	private ZooKeeper zooKeeper;
	private static final String LOCK_ROOT_PATH = "/Locks";
	private static final String LOCK_NODE_PATH = "Lock_";

	private String lockPath;

	//打开zookeeper的链接
	public ZookeeperLock() throws IOException {
		try{
			zooKeeper= new ZooKeeper(IP, 10000, new Watcher() {
				@Override
				public void process(WatchedEvent event) {
					if(event.getType()==Event.EventType.None){
						if(event.getState()==Event.KeeperState.SyncConnected){
							System.out.println("连接创建成功~~~");
							countDownLatch.countDown();
						}
					}
				}
			});
			countDownLatch.await();

		}catch(Exception e){
			e.printStackTrace();
		}
	}
	//监视器对象,监视上一个节点是否被删除\
	private Watcher watcher = new Watcher() {
		@Override
		public void process(WatchedEvent event) {
			System.out.println(event.getPath() + " 前锁释放");
			if(event.getType()== Event.EventType.NodeDeleted){
				synchronized (this) {
					notifyAll();
				}
			}
		}
	};

	/**
	 *  加锁
	 * @throws Exception
	 */
	public void acquireLock() throws Exception{
		//创建锁节点
		createLock();
		//尝试获取锁
		attempLock();
	}

	/**
	 * 创建锁节点
	 * @throws Exception
	 */
	public void createLock() throws Exception{
		//1、打开zookeeper连接

		//2、创建Locks根节点(创建前先用exit判断是否存在,不存在创建)
		Stat stat =  zooKeeper.exists(LOCK_ROOT_PATH,false);
		if(stat == null){
			zooKeeper.create(LOCK_ROOT_PATH,new byte[0],ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
		}

		// 3、创建临时有序节点
		lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" +LOCK_NODE_PATH,new byte[0] ,
				ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

		System.out.println("创建节点成功~~~" + lockPath);
		//进行测试一下~~,看看我们的代码是否有问题~~
	}

	private void attempLock() throws Exception{

		//1、获取locks下的所有子节点
		List<String> list = zooKeeper.getChildren(LOCK_ROOT_PATH,false);

		//2、对子节点进行排序
		Collections.sort(list);

		//3、截取掉前面部分
		int index = list.indexOf(lockPath.substring(LOCK_ROOT_PATH.length()+1));

		//4、对索引进行判断
		if(index == 0) {
			System.out.println("说明是第1位,获取锁成功!");
			return;
		}else {
			//获取上一个节点的路径
			String path = list.get(index-1);
			//监视上一个节点
			Stat stat = zooKeeper.exists(LOCK_ROOT_PATH+"/"+path,watcher); //监视器对象,监视上一个节点是否被删除

			if(stat==null){
				//回调,尝试重新获得锁
				attempLock();
			}else{
				//阻塞等待
				synchronized(watcher){
					watcher.wait();
				}
				//回调,尝试重新获得锁
				attempLock();
			}
		}
	}

	/**
	 * 释放锁
	 * @throws KeeperException
	 * @throws InterruptedException
	 */
	public void releaseLock() throws KeeperException, InterruptedException {
		zooKeeper.delete(lockPath, -1);
		zooKeeper.close();
		System.out.println(" 锁释放:" + lockPath);
}

}

测试调用

public class TicketSeller {
	private void sell(){
		System.out.println("售票开始");
		// 线程随机休眠数毫秒,模拟现实中的费时操作
		int sleepMillis = (int) (Math.random() * 2000);
		try {
			//代表复杂逻辑执行了一段时间
			Thread.sleep(sleepMillis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("售票结束");
	}

	public void sellTicketWithLock() throws Exception {
		ZookeeperLock lock = new ZookeeperLock();
		lock.acquireLock();
		sell();
		lock.releaseLock();
	}

	public static void main(String[] args) throws Exception {
		TicketSeller ticketSeller = new TicketSeller();
		for(int i=0;i<1000;i++){
			ticketSeller.sellTicketWithLock();

		}
	}
}

启动程序测试结果:

main 锁获得, lockPath: /Locks/Lock_0000000472
售票开始
售票结束
 锁释放:/Locks/Lock_0000000472
main 锁创建: /Locks/Lock_0000000474
 等待前锁释放,prelocakPath:Lock_0000000473
/Locks/Lock_0000000473 前锁释放
main 锁获得, lockPath: /Locks/Lock_0000000474
售票开始
售票结束
 锁释放:/Locks/Lock_0000000474

参考文章:https://blog.csdn.net/liyiming2017/article/details/83786331

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot 整合分布式锁有很多种方法,其中一种是使用第三方框架,比如 Redis 和 Zookeeper。 使用 Redis 实现分布式锁可以使用 Redis 的原子操作实现,如 SETNX 命令。 使用 Zookeeper 实现分布式锁可以使用 Zookeeper 的临时有序节点特性。 此外,还有一些开源的分布式锁框架,例如:jedis、curator等。 在使用之前,请仔细研究这些框架的实现原理和使用方法,以保证分布式锁的正确性。 ### 回答2: Spring Boot是一个用于简化Spring应用程序开发的框架,它提供了很多便利的特性和功能。而分布式锁是一种用于保证在分布式系统中多个实例之间的数据一致性的技术。 在Spring Boot中整合分布式锁可以采用多种方式,常用的有基于数据库的分布式锁和基于Redis的分布式锁。下面以基于Redis的分布式锁为例进行说明: 首先,需要引入Redis的依赖,可以使用Spring Data Redis来与Redis进行交互。 接下来,创建一个分布式锁的工具类,该工具类需要实现获取锁和释放锁的方法。获取锁的过程可以使用Redis的setnx方法,该方法在指定的key不存在时才会设置成功,可以用来实现分布式锁的竞争。而释放锁的过程可以使用Redis的del方法来删除锁。 在需要加锁的代码块中,首先通过工具类获取锁,如果获取成功则执行业务逻辑,执行完毕后释放锁。如果获取失败则进行重试或放弃。 需要注意的是,分布式锁的设计要考虑并发性和可靠性,可以采用基于时间的自动释放锁,避免因为锁未被释放导致的死锁等问题。 总结起来,使用Spring Boot整合分布式锁的过程包括引入Redis依赖、创建分布式锁工具类、在需要加锁的代码块中获取锁和释放锁。这样可以保证在分布式环境下保证数据一致性和并发性。 ### 回答3: Spring Boot是一种用于创建和部署独立、可扩展且生产级别的Java应用程序的开发框架。要实现分布式锁整合,我们可以使用Spring Boot提供的各种工具和库来处理分布式锁的相关问题。 首先,我们可以使用Spring Data Redis作为实现分布式锁的主要工具。Redis是一种开源的高性能键值对存储数据库,它具备分布式锁所需的原子性和并发性。我们可以使用Redis的setnx命令来尝试获取锁,并使用expire命令来设置锁的过期时间。在Spring Boot中,我们可以使用Spring Data Redis来操作Redis,并将其集成到我们的应用程序中。 其次,我们可以使用Spring Cloud的分布式锁解决方案,如Zookeeper、Etcd等。这些解决方案提供了高可用、高性能的分布式协调服务,可以用于实现分布式锁。在Spring Boot中,我们可以使用Spring Cloud Zookeeper或Spring Cloud Etcd来创建和管理分布式锁。 另外,我们还可以使用分布式锁的开源库,如Curator、Redlock等。这些库提供了方便易用的分布式锁实现,可以帮助我们更容易地整合和使用分布式锁功能。在Spring Boot中,我们可以将这些库集成到项目中,并使用其提供的API来实现分布式锁。 总结起来,Spring Boot提供了丰富的工具和库来整合和使用分布式锁。我们可以选择合适的工具和库来实现分布式锁的相关功能,并根据实际需求进行配置和使用。无论是使用Redis、Zookeeper、Etcd还是开源库,Spring Boot都提供了相应的支持和集成方式,使得分布式锁整合变得更加简单和便捷。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值