一、基于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实现的更多相关文章

  1. 本地锁、redis分布式锁、zk分布式锁

    本地锁.redis分布式锁.zk分布式锁 https://www.cnblogs.com/yjq-code/p/dotnetlock.html 为什么要用锁? 大型站点在高并发的情况下,为了保持数据最 ...

  2. 借读:分布式锁和双写Redis

      本帖最后由 howtodown 于 2016-10-3 16:01 编辑问题导读1.为什么会产生分布式锁?2.使用分布式锁的方法有哪些?3.本文创造的分布式锁的双写Redis框架都包含哪些内容? ...

  3. 分布式锁的实现之 redis 篇

    为什么需要分布式锁 引入经典的秒杀情景,100件商品供客户抢.如果是单机版的话,我们使用synchronized 或者 lock 都可以实现线程安全.但是如果多个服务器的话,synchronized ...

  4. springboot实现分布式锁(spring integration,redis)

    Springboot实现分布式锁(Spring Integration+Redis) 一.在项目的pom.xml中添加相关依赖 1)Spring Integration依赖 <dependenc ...

  5. .net下 本地锁、redis分布式锁、zk分布式锁的实现

    为什么要用锁? 大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持.比如:分布式锁.分布式事务.有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来 ...

  6. 分布式锁 基于Redis

    分布式锁的实现(基于Redis) 参考:http://www.jb51.net/article/75439.htm http://www.linuxidc.com/Linux/2015-01/1118 ...

  7. Redis 分布式锁,C#通过Redis实现分布式锁(转)

    目录(?)[+] 分布式锁一般有三种实现方式: 可靠性   分布式锁一般有三种实现方式: 1. 数据库乐观锁; 2. 基于Redis的分布式锁; 3. 基于ZooKeeper的分布式锁.本篇博客将介绍 ...

  8. 分布式锁实现(一):Redis

    前言 单机环境下我们可以通过JAVA的Synchronized和Lock来实现进程内部的锁,但是随着分布式应用和集群环境的出现,系统资源的竞争从单进程多线程的竞争变成了多进程的竞争,这时候就需要分布式 ...

  9. 什么是分布式锁及正确使用redis实现分布式锁

    分布式锁 分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性. 举个不太恰当的例子:假设共享的资源就是一个房子,里面有各种书,分布式系统就是要进屋看书的人,分布式锁 ...

随机推荐

  1. ServletConfig获取Servlet的公共参数方法

    web.xml配置: <servlet> <servlet-name>AServlet</servlet-name> <servlet-class>AS ...

  2. Log4Net 日志文件分类保存

    1.app.config <configSections> <section name="log4net" type="log4net.Config.L ...

  3. RenderScript多输入参数

    https://stackoverflow.com/questions/20783830/how-to-use-renderscript-with-multiple-input-allocations ...

  4. 【分库分表】sharding-jdbc—解决的问题

    一.遇到的问题 随着互联网技术和业务规模的发展,单个db的表里数据越来越多,sql的优化已经作用不明显或解决不了问题了,这时系统的瓶颈就是单个db了(或单table数据太大).这时候就涉及到分库分表的 ...

  5. JS的Scope

    关键字:域(scope),闭包(closure),关键字this,命名空间(namespace),函数域(function scope),全局域(global scope),词法作用域(lexical ...

  6. Linux读书笔记1/2章

    linux的内核设计: 第一章 1.1Linux历史: 历经时间的考验,今天Unix已经发展成一个支持抢占式多任务.多线程.虚拟内存.换页.动态链接.TCP/Ip网络的现代化操作系统. 1.2追寻Li ...

  7. 学习Windows(BAT)、Linux(Shell)编程,并分别写一个脚本文件解决自己的一个问题

    delete: @echo off echo Press any key to delete this file.pause del %0 ip: @echo off color a Title 端口 ...

  8. HBase相关问题

    HBase和Hive的异同之处? 共同点:HBase与Hive都是架构在Hadoop之上,底层存储都是使用HDFS 区别: 1). Hive是建立在Hadoop之上为了减少MapReduce jobs ...

  9. MR案例:倒排索引 && MultipleInputs

    本案例采用 MultipleInputs类 实现多路径输入的倒排索引.解读:MR多路径输入 package test0820; import java.io.IOException; import j ...

  10. mysql系列之多实例介绍

    介绍: mysql多实例,简单理解就是在一台服务器上,mysql服务开启多个不同的端口(如3306.3307),运行多个服务进程.这些 mysql 服务进程通过不同的 socket来监听不同的数据端口 ...