zookeeper实现分布式锁
来源:互联网 发布:风靡网络的恐怖推理图 编辑:程序博客网 时间:2024/06/04 00:23
接口:
import java.util.concurrent.TimeUnit;public interface DistributedLock { public void getLock() throws Exception; public boolean getLock(long time,TimeUnit timeUnit) throws Exception; public void releaseLock();}
核心公用代码:
import java.util.Collections;import java.util.Comparator;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.CountDownLatch;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;import org.I0Itec.zkclient.IZkDataListener;import org.I0Itec.zkclient.ZkClient;import org.I0Itec.zkclient.exception.ZkNoNodeException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;public class BaseDistributedLock { private final static Logger logger = LoggerFactory.getLogger(BaseDistributedLock.class); private final ZkClient client; private final String lockPath; private final String baseLockName; private final String lockName; private ThreadPoolTaskExecutor taskExecutor; private static final Integer MAX_RETRY_COUNT = 10; public BaseDistributedLock(ZkClient zkClient,String baseLockName,String lockName,ThreadPoolTaskExecutor taskExecutor){ this.client = zkClient; this.baseLockName = baseLockName; this.lockName = lockName; this.lockPath = baseLockName.concat("/").concat(lockName); this.taskExecutor = taskExecutor; } /** * 获取锁资源 * @param time * @param timeUnit * @return * @throws Exception */ public String doGetLock(long time, TimeUnit timeUnit) throws Exception{ String path = null; if(timeUnit != null){ //存在超时时间 Future<String> future = taskExecutor.submit(new GetLock()); try { path = future.get(time, timeUnit); } catch (TimeoutException e) { //超时则中断获取锁的方法 future.cancel(true); } }else { //没有超时时间 path = waitLock(); } return path; } /** * 创建path,调用锁等待方法 * @return * @throws Exception */ public String waitLock()throws Exception{ int retrycount = 1; String path = null; //创建零时节点,重试次数为10次 try { path = createLockNode(); } catch (Exception e) { if(retrycount++ < MAX_RETRY_COUNT){ createLockNode(); }else { throw e; } } return doWaitLock(path); } /** * 等待锁资源(核心逻辑) * @return 创建的路径 * @throws Exception */ public String doWaitLock(String path) throws Exception{ boolean getTheLock = false; boolean doDelete = false; //判断是否获取到锁资源 try { while (!getTheLock) { //获取该baseLockName路径下的所有子节点,并排序 List<String> children = getSortedChildren(); String sequenceNodeName = path.substring(baseLockName.length()+1); int pathIndex = children.indexOf(sequenceNodeName); if(pathIndex < 0){ throw new ZkNoNodeException("节点没有找到: " + sequenceNodeName); } if(pathIndex == 0){ //获取到锁资源 getTheLock = true; return path; }else { //获取前一个节点的path String previousPath = baseLockName.concat("/").concat(children.get(pathIndex-1)); //监听该节点 final CountDownLatch latch = new CountDownLatch(1); final IZkDataListener previousListener = new IZkDataListener() { // 次小节点删除事件发生时,让countDownLatch结束等待 // 此时还需要重新让程序回到while,重新判断一次! public void handleDataDeleted(String dataPath) throws Exception { latch.countDown(); } public void handleDataChange(String dataPath, Object data) throws Exception { return; } }; try { client.subscribeDataChanges(previousPath, previousListener); latch.await(); } catch (ZkNoNodeException e) { logger.error("注册监听事件出现异常:"+e.getMessage()); } finally { client.unsubscribeDataChanges(previousPath, previousListener); } } } } catch (Exception e) { doDelete = true; throw e; }finally { if(doDelete){ deletePath(path); } } return null; } /** * 创建临时节点 * @return * @throws Exception */ private String createLockNode()throws Exception { return client.createEphemeralSequential(lockPath, null); } /** * 如果该路径存在,那么就删除 * @param path */ public void deletePath(String path){ client.delete(path); } /** * 另起一个线程去获取锁资源,主线程监听超时时间 * @author 13376 * */ class GetLock implements Callable<String>{ @Override public String call() throws Exception { return waitLock(); } } /** * 顺序获取所有的子节点 * @return * @throws Exception */ private List<String> getSortedChildren() throws Exception { try { List<String> children = client.getChildren(baseLockName); Collections.sort(children, new Comparator<String>() { public int compare(String lhs, String rhs) { return getLockNodeNumber(lhs, lockName).compareTo( getLockNodeNumber(rhs, lockName)); } }); return children; } catch (ZkNoNodeException e) { client.createPersistent(baseLockName, true); return getSortedChildren(); } } /** * 获取零时节点名后面的自增长的数字 * @param str * @param lockName * @return */ private String getLockNodeNumber(String str, String lockName) { int index = str.lastIndexOf(lockName); if (index >= 0) { index += lockName.length(); return index <= str.length() ? str.substring(index) : ""; } return str; }}
对外暴露的接口方法:
import java.util.concurrent.TimeUnit;import org.I0Itec.zkclient.ZkClient;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;public class ZooDistributedLock extends BaseDistributedLock implements DistributedLock { private static final String LOCK_NAME = "lock-"; private String path; public ZooDistributedLock(ZkClient zkClient,String baseLockName,ThreadPoolTaskExecutor taskExecutor){ super(zkClient,baseLockName,LOCK_NAME,taskExecutor); } @Override public void getLock() throws Exception { if(!getLock(-1,null)){ throw new RuntimeException("连接异常,"+path+"路径下获取所失败"); } } @Override public boolean getLock(long time, TimeUnit timeUnit) throws Exception { path = this.doGetLock(time,timeUnit); return path != null; } @Override public void releaseLock() { this.deletePath(path); }}
阅读全文
0 0
- ZooKeeper实现分布式锁
- Zookeeper实现分布式锁
- ZooKeeper实现分布式锁
- ZooKeeper 实现分布式锁
- zookeeper实现分布式锁
- zookeeper实现分布式锁
- zookeeper实现分布式锁
- Zookeeper实现分布式锁
- Zookeeper实现分布式锁
- zookeeper实现分布式锁
- Zookeeper分布式锁实现
- Zookeeper 实现分布式锁
- zookeeper实现分布式锁
- Zookeeper分布式锁实现
- zookeeper实现分布式锁
- zookeeper实现分布式锁
- Zookeeper实现分布式锁
- zookeeper实现分布式锁
- 第四周项目六C/C++链表:多项式求和
- Mahmoud and a Triangle 【codeforces】 【水题】
- Cookie&Session
- 文章标题
- Pycharm ++++ Django项目测试
- zookeeper实现分布式锁
- vim
- JavaScript外链判断,并弹窗提示
- Spring 框架详解(2)
- 权限管理
- POJ1745-DP初探
- 常用深度学习框架简介
- opencv3.2 安装报错解决方法
- 数论总结