分布式锁-基于ZK和Redis实现
一、基于zookeeper实现分布式锁
1.1 Zookeeper的常用接口
package register; import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat; public class BaseZookeeper implements Watcher{ public BaseZookeeper(){} public BaseZookeeper(String host){
this.connectZookeeper(host);
} private ZooKeeper zookeeper; //超时时间
private static final int SESSION_TIME_OUT = ;
private CountDownLatch countDownLatch = new CountDownLatch(); public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected) {
//System.out.println("Watch received event");
countDownLatch.countDown();
}
} //连接zookeeper
protected void connectZookeeper(String host){
try {
zookeeper = new ZooKeeper(host, SESSION_TIME_OUT, this);
countDownLatch.await();
//System.out.println("zookeeper connection success");
} catch (Exception e) {
e.printStackTrace();
}
} //创建节点
protected String createNode(String path, String data){
try {
//永久节点
String result = this.zookeeper.create(path, data.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//临时节点(会话关闭就删除了,调用close后就自动删除了)
//String result = this.zookeeper.create(path, data.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("createNode: " + result);
return result;
} catch (Exception e) {
//e.printStackTrace();
return null;
}
} //创建多级节点
//String path = "/dubbo/server/com.wzy.server.OrderServer";
protected boolean createMultNode(String path){ String[] paths = path.split("/");
String realPath = "/";
for (int i=; i<paths.length; i++) {
realPath += paths[i];
String result = createNode(realPath, ""); if (result == null) {
return false;
}
realPath += "/";
}
return true;
} //获取路径下所有子节点
protected List<String> getChildren(String path){
try {
List<String> children = zookeeper.getChildren(path, false);
return children;
} catch (Exception e) {
//当路径已经是根节点(没有子节点)时,就会抛异常
return null;
} } //获取节点上面的数据
protected String getData(String path) throws KeeperException, InterruptedException{
byte[] data = zookeeper.getData(path, false, null);
if (data == null) {
return "";
}
return new String(data);
} //设置节点信息
protected Stat setData(String path, String data){
try {
getData(path);
Stat stat = zookeeper.setData(path, data.getBytes(), -);
return stat;
} catch (Exception e) {
//String result = createNode(path,"");
return null;
} } //删除节点
protected boolean deleteNode(String path){
if (!path.startsWith("/")) {
path = "/" + path;
}
try {
zookeeper.delete(path, -);
} catch (InterruptedException e) {
return false;
} catch (KeeperException e) {
return false;
}
return true;
} //获取创建时间
protected String getCTime(String path) throws KeeperException, InterruptedException{
Stat stat = zookeeper.exists(path, false);
return String.valueOf(stat.getCtime());
} //获取某个路径下孩子的数量
protected Integer getChildrenNum(String path) throws KeeperException, InterruptedException{
int childenNum = zookeeper.getChildren(path, false).size();
return childenNum;
} //监听节点是否被删除
protected void watchIsDel(final String path) throws Exception{
zookeeper.exists(path, new Watcher() {
public void process(WatchedEvent watchedEvent) {
Event.EventType type = watchedEvent.getType();
if (Event.EventType.NodeDeleted.equals(type)) {
System.out.println("结点 " + path + "被删除了");
}
}
});
} //关闭连接
public void closeConnection() {
if (zookeeper != null) {
try {
zookeeper.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
package register; import framework.URL; import java.util.List;
import java.util.Random; /**
* zk 的注册工具
*/
public class ZkRegister extends BaseZookeeper { private static String ZK_HOST = "127.0.0.1:2181";
private final String SERVER_ADDRESS = "/dubbo/server";
private final String ROOT_ADDRESS = "/dubbo"; public ZkRegister(){
super(ZK_HOST);
} public void setZkHost(String host){ZkRegister.ZK_HOST = host;} /**
* 注册服务
* @param serverInterface
* @param url
* @return
*/
public boolean regist(Class serverInterface, URL url){
if (null != getChildren(ROOT_ADDRESS)){
deleteNodeRF(ROOT_ADDRESS);
}
return addAddressToNode(SERVER_ADDRESS + "/" + serverInterface.getName(), new String[]{url.getAddress()});
} /**
* 从地址列表里随机获取一个地址
* @param serverInterface
* @return
*/
public String getURLRandom(Class serverInterface){
List<String> urls = getChildren(SERVER_ADDRESS + "/" + serverInterface.getName());
return urls.get(new Random().nextInt(urls.size()));
} /**
* 向节点添加服务地址
* @param nodePath
* @param address
* @return
* String path = "/dubbo/server/com.wzy.server.OrderServer";
* String[] ip = new String[]{"192.168.37.1","192.168.37.2","192.168.37.3"};
*/
public boolean addAddressToNode (String nodePath, String[] address) {
if (!nodePath.startsWith("/")) {
nodePath = "/" + nodePath;
} if (null == getChildren(nodePath)){
createMultNode(nodePath);
}
for (int i=; i<address.length; i++) {
String newPath = nodePath + "/" + address[i];
String result = createNode(newPath,"");
if (null == result) {
return false;
}
}
return true;
} public boolean deleteNodeRF (String rootPath) {
return deleteNodeRF(rootPath, rootPath);
}
/**
* 删除节点及其子目录
* @param rootPath
* @return
*/
private boolean deleteNodeRF (String rootPath, String parentPath) {
if (!rootPath.startsWith("/")) {
rootPath = "/" + rootPath;
}
List<String> childs = getChildren(rootPath);
if (childs.size() > ) {
//递归
for (String child : childs) {
deleteNodeRF(rootPath + "/" + child, rootPath);
}
} else {
System.out.println("delete: " + rootPath + " " + deleteNode(rootPath));
}
System.out.println("delete: " + parentPath + " " + deleteNode(parentPath)); return true;
}
}
1.2 基于zk实现分布式锁
package lock; import org.apache.zookeeper.*; import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; /**
* Zookeeper实现分布式锁
*/
public class ZookeeperLock implements Lock { private ThreadLocal<ZooKeeper> zk = new ThreadLocal<ZooKeeper>();
private String host = "localhost:2181"; private final String LOCK_NAME = "/LOCK";
private ThreadLocal<String> CURRENT_NODE = new ThreadLocal<String>(); private void init() {
if (zk.get() == null) {
synchronized (ZookeeperLock.class) {
if (zk.get() == null) {
try {
zk.set( new ZooKeeper(host, , new Watcher() {
public void process(WatchedEvent watchedEvent) {
// do nothing..
}
}));
} catch (Exception e) {
e.printStackTrace();
} }
}
}
} public void lock() {
init();
if (tryLock()) {
System.out.println("get lock success");
}
} public boolean tryLock() {
String node = LOCK_NAME + "/zk_";
try {
//创建临时顺序节点 /LOCK/zk_1
CURRENT_NODE.set(zk.get().create(node, new byte[], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL));
//zk_1,zk_2
List<String> list = zk.get().getChildren(LOCK_NAME, false);
Collections.sort(list);
System.out.println(list);
String minNode = list.get(); if ((LOCK_NAME + "/" + minNode).equals(CURRENT_NODE.get())) {
return true;
} else {
//等待锁
Integer currentIndex = list.indexOf(CURRENT_NODE.get().substring(CURRENT_NODE.get().lastIndexOf("/") + ));
String preNodeName = list.get(currentIndex - ); //监听前一个节点删除事件
final CountDownLatch countDownLatch = new CountDownLatch();
zk.get().exists(LOCK_NAME + "/" + preNodeName, new Watcher() {
public void process(WatchedEvent watchedEvent) {
if (Event.EventType.NodeDeleted.equals(watchedEvent.getType())) {
countDownLatch.countDown();
System.out.println(Thread.currentThread().getName() + "唤醒锁..");
}
}
}); System.out.println(Thread.currentThread().getName() + "等待锁..");
countDownLatch.await();//在变成0之前会一直阻塞 }
} catch (Exception e) {
e.printStackTrace();
return false;
} return true;
} public void unlock() {
try {
zk.get().delete(CURRENT_NODE.get(), -);
CURRENT_NODE.remove();
zk.get().close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
} } public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
} public void lockInterruptibly() throws InterruptedException { } public Condition newCondition() {
return null;
}
}
二、基于Redis实现分布式锁
package lock; import redis.clients.jedis.Jedis; import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; /**
* Redis实现分布式锁
*/
public class RedisLock implements Lock { ThreadLocal<Jedis> jedis = new ThreadLocal<Jedis>(); private static String LOCK_NAME = "LOCK";
private static String REQUEST_ID = null; public RedisLock (String requestId) {
RedisLock.REQUEST_ID = requestId;
if (jedis.get() == null) {
jedis.set(new Jedis("localhost"));
}
}
public void lock() {
if (tryLock()) {
//jedis.set(LOCK_NAME, REQUEST_ID);
//jedis.expire(LOCK_NAME, 1000);//设置过期时间 //问题:上面两句代码不存在原子性操作,所以用下面一句代码替换掉
jedis.get().set(LOCK_NAME, REQUEST_ID, "NX", "PX", );
}
} public boolean tryLock() {
while (true) {
//key不存在时设置值,存在则设置失败。设置成功返回1,设置失败返回0
Long lock = jedis.get().setnx(LOCK_NAME, REQUEST_ID);
if (lock == ) {
return true;
}
}
} public void unlock() {
//问题:保证不了原子性
//String value = jedis.get(LOCK_NAME);
//if (REQUEST_ID.equals(value)) {
// jedis.del(LOCK_NAME);
//} String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
jedis.get().eval(script, Collections.singletonList(LOCK_NAME), Collections.singletonList(REQUEST_ID));
jedis.get().close();
jedis.remove(); } public Condition newCondition() {
return null;
} public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
} public void lockInterruptibly() throws InterruptedException { }
}
分布式锁-基于ZK和Redis实现的更多相关文章
- 本地锁、redis分布式锁、zk分布式锁
本地锁.redis分布式锁.zk分布式锁 https://www.cnblogs.com/yjq-code/p/dotnetlock.html 为什么要用锁? 大型站点在高并发的情况下,为了保持数据最 ...
- 借读:分布式锁和双写Redis
本帖最后由 howtodown 于 2016-10-3 16:01 编辑问题导读1.为什么会产生分布式锁?2.使用分布式锁的方法有哪些?3.本文创造的分布式锁的双写Redis框架都包含哪些内容? ...
- 分布式锁的实现之 redis 篇
为什么需要分布式锁 引入经典的秒杀情景,100件商品供客户抢.如果是单机版的话,我们使用synchronized 或者 lock 都可以实现线程安全.但是如果多个服务器的话,synchronized ...
- springboot实现分布式锁(spring integration,redis)
Springboot实现分布式锁(Spring Integration+Redis) 一.在项目的pom.xml中添加相关依赖 1)Spring Integration依赖 <dependenc ...
- .net下 本地锁、redis分布式锁、zk分布式锁的实现
为什么要用锁? 大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持.比如:分布式锁.分布式事务.有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来 ...
- 分布式锁 基于Redis
分布式锁的实现(基于Redis) 参考:http://www.jb51.net/article/75439.htm http://www.linuxidc.com/Linux/2015-01/1118 ...
- Redis 分布式锁,C#通过Redis实现分布式锁(转)
目录(?)[+] 分布式锁一般有三种实现方式: 可靠性 分布式锁一般有三种实现方式: 1. 数据库乐观锁; 2. 基于Redis的分布式锁; 3. 基于ZooKeeper的分布式锁.本篇博客将介绍 ...
- 分布式锁实现(一):Redis
前言 单机环境下我们可以通过JAVA的Synchronized和Lock来实现进程内部的锁,但是随着分布式应用和集群环境的出现,系统资源的竞争从单进程多线程的竞争变成了多进程的竞争,这时候就需要分布式 ...
- 什么是分布式锁及正确使用redis实现分布式锁
分布式锁 分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性. 举个不太恰当的例子:假设共享的资源就是一个房子,里面有各种书,分布式系统就是要进屋看书的人,分布式锁 ...
随机推荐
- Swoole学习(二)Swoole之TCP服务器的创建
环境:Centos6.4,PHP环境:PHP7 <?php //创建TCP服务器 /** * $host 是swoole需要监听的ip,如果要监听本地,不对外服务,那么就是127.0.0.1;如 ...
- 虚拟中没有eth0
进行虚拟机的软拷贝和硬拷贝,或直接从一台机器上拷贝虚拟机硬盘文件到另一台机子的虚拟机上时,发现通过修改/etc/network/interfaces配置的IP没用,输入ifconfig,发现根本就没有 ...
- linux 分区格式化
要对一个u盘进行分区 windows上直接格式化就行了,但是我的u盘 由于之前做成的系统把u盘分成三个分区,windows只能格式化第一个分区其他两个分区只能看着,理论上windows上也有dd之类的 ...
- awk循环语句-【AWK学习之旅】
AWK中两种循环语句:if-else 和 while 控制流语句: 1.if-else 求总数,平均值: [root@monitor awkdir]# awk '$3>6 {n = n ...
- 20145313张雪纯 《Java程序设计》第6周学习总结
20145313张雪纯 <Java程序设计>第6周学习总结 教材学习内容总结 将数据从来源中取出,可以使用输入串流:将数据写入目的地,可以使用输出串流. 输入串流代表对象为java.io. ...
- 《Java程序设计》 第2周学习总结
20145318 <Java程序设计>第2周学习总结 教材学习内容总结 short,2字节:int,4字节:long,8字节:byte,1字节:float,4字节:double,8字节:c ...
- CORE MVC 自定义认证
微软的认证体系,集成了EF,和它的表结构,对于我们已有的系统,或者想高度自定义的人,该怎么办呢? 答案在: https://docs.microsoft.com/en-us/aspnet/core/s ...
- javaWeb中JNDI的使用,为什么要加java:comp/env前缀
转载自(http://blog.csdn.net/guodongsoft/article/details/52399527) 我们在使用JNDI调用某个对象时,会有下述两种方式 context.loo ...
- contos LINUX搭建LAMP笔记
LINUX搭建LAMP笔记 .YUM:Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器.基于R ...
- springMVC入门案例
1.配置文件的web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xs ...