实现分布式锁有很多种方式:

 1:数据库方式: 谁先插入数据库值成功, 谁就获取锁。

 2: 缓存方式

 3: zookeeper 实现分布式锁, 推荐这种方式

 

zk实现分布式锁的原理及流程: 临时节点 + 事件通知 + 信号量, 临时节点的生命周期是连接断开则会删除。

   zk有四种节点类型

    1: 持久化节点

    2:临时节点

    3:持久化顺序节点

    4: 临时顺序节点。

   zk 的事件通知 watcher.

实现分布式锁 流程:

  1: 连接zk

  2: 创建临时节点, 如果创建成功, 则获取锁, 代码执行完毕, 释放锁(也就是关闭zk连接)。

                               如果创建失败,则代表有服务创建了节点获取了锁, 此时则使用信号量等待。

 3: 节点删除的通知, 如果有节点被删除的通知过来了, 则唤醒信号量, 重新尝试获取锁。

代码:

1: 锁接口
/** * ClassName: Lock * Function: 定义锁 * date: 2019年7月10日 下午9:44:32 * * @author
tangjiandong */ public interface Lock { void getLock(); void unlock(); }
2: 锁的两个实现:
/** * Project Name:distributed * File Name:ZookeeperAbstractLock.java *
Package Name:com.tang.service * Date:2019年7月10日 下午9:52:06 * Copyright (c) 2019,
All Rights Reserved. * */ package com.tang.service; import
java.util.concurrent.CountDownLatch; import org.I0Itec.zkclient.ZkClient; /** *
ClassName: ZookeeperAbstractLock * Function: TODO ADD FUNCTION. * date:
2019年7月10日 下午9:52:06 * * @author tangjiandong */ public abstract class
ZookeeperAbstractLock implements Lock { private static final String
connectAddress = "127.0.0.1:2181"; //连接地址 private static final int timeOut =
5000; //超时时间 protected static final String path = "/lock"; //创建的节点名称 protected
ZkClient zkClient = new ZkClient(connectAddress); //连接建立 protected
CountDownLatch countDownLatch = null; //信号量计数器 /** * * @see
com.tang.service.Lock#getLock() */ @Override public void getLock() { //是否获取锁
if(trylock()) { System.out.println("---------获取锁!"); }else { //如果等待到了锁,则继续获取锁,
否则继续等待 waitLock(); //尝试获取锁 getLock(); } } //是否获取锁 abstract boolean trylock();
//等待锁 abstract void waitLock(); /** *关闭连接, 释放锁 * @see
com.tang.service.Lock#unlock() */ @Override public void unlock() { if(null !=
zkClient) { zkClient.close(); System.out.println("---------释放锁!"); } } }
 
/** * Project Name:distributed * File Name:ZookeeperDistributedLock.java *
Package Name:com.tang.service * Date:2019年7月10日 下午10:10:23 * Copyright (c)
2019, All Rights Reserved. * */ package com.tang.service; import
java.util.concurrent.CountDownLatch; import
org.I0Itec.zkclient.IZkDataListener; /** * ClassName: ZookeeperDistributedLock
* Function: 获取锁与等待锁的实现 * date: 2019年7月10日 下午10:10:23 * * @author tangjiandong
*/ public class ZookeeperDistributedLock extends ZookeeperAbstractLock{ /** *
获取锁 * @return * @see com.tang.service.ZookeeperAbstractLock#trylock() */
@Override boolean trylock() { try { zkClient.createEphemeral(path); //创建临时节点
return true; //创建成功则获取锁 } catch (Exception e) { return false; //创建失败则没有获取到锁,
需要等待 } } /** * 等待锁 * @see com.tang.service.ZookeeperAbstractLock#waitLock() */
@Override void waitLock() { //创建节点的监听 IZkDataListener iZkDataListener = new
IZkDataListener() { //节点被删除的通知 @Override public void handleDataDeleted(String
dataPath) throws Exception { if(null != countDownLatch) {
countDownLatch.countDown(); //计数器减一,唤醒等待 } } //节点改变的通知 @Override public void
handleDataChange(String dataPath, Object data) throws Exception { // TODO
Auto-generated method stub } }; //注册监听 try {
zkClient.subscribeDataChanges(path, iZkDataListener); } catch (Exception e) {
System.out.println("---------节点注册监听异常!"); } if(zkClient.exists(path))
//如果节点存在了,则等待, { countDownLatch = new CountDownLatch(1); try {
countDownLatch.await(); //可加上超时等待, 防止延迟通知导致死锁 //countDownLatch.await(1000,
TimeUnit.SECONDS); } catch (InterruptedException e) { //节点等待失败
System.out.println("---------节点等待异常!"); e.printStackTrace(); } } //删除监听
zkClient.unsubscribeDataChanges(path, iZkDataListener); } }
 3:调用
/** * Project Name:distributed * File Name:CreateNumber.java * Package
Name:com.tang.number * Date:2019��7��9�� ����8:38:45 * Copyright (c) 2019,
���쳤����Ϸֹ�˾ All Rights Reserved. * */ package com.tang.number; import
java.util.concurrent.locks.Lock; import
java.util.concurrent.locks.ReentrantLock; import
org.springframework.beans.factory.annotation.Autowired; import
org.springframework.stereotype.Service; import
com.tang.service.ZookeeperDistributedLock; /** * ClassName: CreateNumber *
Function: TODO ADD FUNCTION. * date: 2019��7��9�� ����8:38:45 * * @author
tangjiandong */ public class CreateNumber implements Runnable{ private
com.tang.service.Lock lock = new ZookeeperDistributedLock(); //创建锁 /** * * @see
java.lang.Runnable#run() */ @Override public void run() { //synchronized (this)
{ lock.getLock(); try { getNumber(); } finally { lock.unlock(); } //} } public
void getNumber() { String createJjdbh = JjdbhUtils.createJjdbh(null);
System.out.println(createJjdbh); } public static void main(String[] args) { for
(int i = 0; i < 100; i++) { new Thread( new CreateNumber()).start(); } } }
 

技术
©2019-2020 Toolsou All rights reserved,
java实现抢红包功能2021年2月程序员工资统计,平均15144元可怕的不是堕落,而是清楚自己在堕落java简单的抽奖算法,抽奖DemoPYTHON入门期末复习汇总惹什么猫都别惹熊猫!「功夫熊猫」20年对人类拿下4血软件测试之BUG描述JS 的骚操作程序员因拒绝带电脑回家被开除,获赔 19.4 万元vue组件页面高度根据屏幕大小自适应