zookeeper中锁分两种:公平锁和非公平锁
公平锁就是排队,一个一个来
非公平锁就是谁抢到谁得
zookeeper公平锁:
zookeeper公平锁是基于它的临时有序节点实现的,当并发访问某一个接口后,会在zookeeper中创建一个临时有序节点,并且这些节点名称都是一样的,当时zookeeper会在名称后加上一个序号,每一个节点只监听比他序号小的,当节点发现他是最小 的就会获取锁资源,如果不是最小的就会一直在那等着。
zookeeper分布式锁和redis分布式锁的区别:
redis分布式锁是基于key实现的,并且有超时时间问题的发生
zookeeper分布式锁基于临时节点实现的,不会有超时问题发生,一旦超时直接报错,断开连接后会清除临时节点信息
zookeeper公平锁具体案例: springboot写的
步骤一:在pom.xml文件中改成2.0.6版本,然后导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version><!--改成了2.0.6-->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>zookeeper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zookeeper</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--zookeeper客户端-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<!--zkclient-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
步骤二:创建连接zookeeper的工具类
本案例将该类命名为:ConnectionZK
package com.qf.zookeeper;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.Test;
import java.util.List;
public class ConnectionZK {
//这里是一个工具类方法,专门获得连接对象,用于调用各种方法
public static CuratorFramework getCf(){
//指定重试策略。每隔四秒重试一次,一共重试2次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 2);//每隔四秒触发一次,重试两次
//连接zookeeper的客户端对象
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString("192.168.22.131:2181,192.168.22.131:2182,192.168.22.131:2183")//连接zookeeper集群中的所有zookeeper。格式: zookeeper的ip:zookeeper的端口号
.connectionTimeoutMs(6000)//超时时间,6秒
.retryPolicy(retryPolicy)//设置超时处理策略
.build();
//开启连接
cf.start();
return cf;//返回zookeeper连接对象,用于节点和数据的创建
}
}
步骤三:在controller创建使用锁的测试类
本案例将该类命名为:LookController
package com.qf.controller;
import com.qf.zookeeper.ConnectionZK;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.TimeUnit;
@Controller
@RequestMapping("/lock")
public class LookController {
private static int i=10000;
private static int j=0;
@RequestMapping("/man-a-lock")
@ResponseBody
public String manALock(){
//获取客户端
CuratorFramework cf = ConnectionZK.getCf();
//创建zookeeper实现的公平锁.公平锁是zookeeper自带的
InterProcessMutex lock = new InterProcessMutex(cf, "/man-a-lock");//第一个参数是连接zookeeper的对象,第二个是指定在那个节点下面创建临时有序节点,没创建也行
try{//zookeeper非公平锁才加trycache
//lock.acquire //慢慢排队,无论多慢都排队
//加锁,未解锁时并发会出现i和j加起来不等于10000
if (lock.acquire(1, TimeUnit.SECONDS)){ //慢慢排队,超过一秒就不排了
Thread.sleep(10);
i--;
j++;
//解锁
lock.release();
}else {
System.out.println("用户太多,被挤爆了!!");
}
} catch (Exception e) {
System.out.println("没有获取到锁资源");
}finally {
cf.close();//关闭客户端,执行完,必须关闭
}
return "i="+i+";j="+j;
}
}
公平锁案例结构图:
zookeeper非公平锁:
使用的是临时节点。公平锁使用的是临时有序节点
用户想获取到锁资源,用户就尝试创建指定的一个节点,如果节点存在,说明锁资源正在占用,直接抛出异常,try-catch中给用户提示,如果创建节点成功,线程成功的获取到了锁资源.
如果出现了死锁?
因为创建的时临时节点,如果出现异常,那么客户端自动断开连接,临时节点自动被删除.
zookeeper非公平锁具体案例:
步骤一:在pom.xml文件中修改版本并导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version><!--改成了2.0.6-->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>zookeeper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zookeeper</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--zookeeper客户端-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<!--zkclient-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
步骤二:创建获取zookeeper连接对象的工具类
将该类命名为:ConnectionZK
package com.qf.zookeeper;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.Test;
import java.util.List;
public class ConnectionZK {
//这里是一个工具类方法,专门获得连接对象,用于调用各种方法
public static CuratorFramework getCf(){
//指定重试策略。每隔四秒重试一次,一共重试2次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 2);//每隔四秒触发一次,重试两次
//连接zookeeper的客户端对象
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString("192.168.22.131:2181,192.168.22.131:2182,192.168.22.131:2183")//连接zookeeper集群中的所有zookeeper。格式: zookeeper的ip:zookeeper的端口号
.connectionTimeoutMs(6000)//超时时间,6秒
.retryPolicy(retryPolicy)//设置超时处理策略
.build();
//开启连接
cf.start();
return cf;//返回zookeeper连接对象,用于节点和数据的创建
}
}
步骤三:创建使用非公平锁的类
本案例将该类命名为:LookController
package com.qf.controller;
import com.qf.zookeeper.ConnectionZK;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.zookeeper.CreateMode;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.TimeUnit;
@Controller
@RequestMapping("/lock")
public class LookController {
private static int i=10000;
private static int j=0;
@RequestMapping("/not-man-a-lock")
@ResponseBody
public String notManLock(){
//获取连接对象
CuratorFramework cf=ConnectionZK.getCf();
//声明锁节点名称
String lockName = "/not-man-a-lock";//节点必须写/
//创建临时节点
try {
//开锁
cf.create().withMode(CreateMode.EPHEMERAL).forPath(lockName);//PERSISTENT持久节点、PERSISTENT_SEQUENTIAL持久有序节点、EPHEMERAL临时节点、EPHEMERAL_SEQUENTIAL临时有序节点
//获取到锁资源,操作
i--;
j++;
//解锁
cf.delete().forPath(lockName);
} catch (Exception e) {
System.out.println("没有获取到锁资源!!!!!");
}finally {
cf.close();
}
return "i="+i+";j="+j;
}
}
非公平锁的结构图:
非公平锁和公平锁的启动类没变,springboot会自动扫描controller注解