Zookeeper分布式锁

线程进程资源竞争
线程进程资源竞争
当有一个线程或进程在对资源进行操作时,其他线程或进程都不可以对这个资
原进行操作,直到该线程或进程完成操作,其他线程或进程才能对该资源进
行操作,而其他线程或进程又处于等待状态。
在这里插入图片描述
线程进程同步的方式和机制
临界区
通过对多线程的串行化来访问公共资源或一段代码
synchronized 修饰的java方法
仅用于线程同步

互斥量
采用互斥对象机制。
只有拥有互斥对象的线程才有访问公共资
源竞争
的问题
源的权限
synchronized 修饰的代码块
java.util.concurrent.locks.Lock
分布式锁的主要实现机制

信号量
它允许多个任务在同一时刻访问同一资源,但是需要限制在同一
时刻访问此资源的最大线程数目;
解决执
行顺序
CountDownLatch,CyclicBarrier和Semaphore
的问题

事件
通过通知操作的方式来保持任务的同步,还可以方便实现对多个
任务的优先级比较的操作

基于数据实现分布式锁
性能较差,容易出现单点故障
锁没有失效事件,容易死锁。
非阻塞式
不可重入

基于缓存实现分布式锁
锁没有失效事件,容易死锁
非阻塞式
不可重入

基于Zookeeper实现分布式锁
实现相对简单
可靠性高
性能较好

Zookeeper应用场景
数据发布订阅
负载均衡
命名服务
分布式协调
集群管理
配置管理
分布式队列
分布式锁

Zookeeper实战分布式锁
场景描述
在线程高并发场景下,生成唯一的订单编号
如:2017-10-14-20-52-33-01
年 月 日 时 分 秒 序号

在这里插入图片描述
代码


#####生成订单号######
import java.text.SimpleDateFormat;
import java.util.Date;

//生成订单号
public class OrderNumGenerator {
	private static int count = 0;
    //生成订单号
	public String getOrderNumber() {
		SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
		return smt.format(new Date()) + "-" + ++count;
	}

}
#####订单业务逻辑######
public class OrderService implements Runnable {
	private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
	private static Object oj = new Object();
	private Lock lock = new ZookeeperDistrbuteLock();

	public void run() {
		getNumber();
	}

	public void getNumber() {
		// synchronized (oj) {
		lock.getLock();
		String orderNumber = orderNumGenerator.getOrderNumber();
		System.out.println("获取订单号:" + orderNumber);
		lock.unLock();
		// }

	}

	public static void main(String[] args) {
		for (int i = 0; i < 100; i++) {
			new Thread(new OrderService()).start();
		}
	}

}

#####lock接口 ######
public interface Lock {
	// 获取锁
	public void getLock();
    // 释放锁
	public void unLock();
}

#####ZookeeperAbstractLock抽象类接口 ######
public abstract class ZookeeperAbstractLock implements Lock {
	private static final String CONNECT_ADDRES = "192.168.110.159:2181,192.168.110.160:2181,192.168.110.162:2181";

	protected ZkClient zkClient = new ZkClient(CONNECT_ADDRES);
	protected String PATH = "/lock";

	public void getLock() {
		// 如果当前节点已经存在,则等待
		if (tryLock()) {
			System.out.println("获取到锁 get");
		} else {
			// 等待
			waitLock();
			// 重新获取锁
			getLock();
		}
	}

	protected abstract void waitLock();

	protected abstract boolean tryLock();

	public void unLock() {
		if (zkClient != null) {
			zkClient.close();
		}
		System.out.println("已经释放锁...");
	}
#####ZookeeperAbstractLock抽象类接口 ######
//实现锁
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
	private CountDownLatch countDownLatch = new CountDownLatch(1);

	@Override
	protected boolean tryLock() {
		try {
			zkClient.createEphemeral(PATH);
			// 创建成功
			return true;
		} catch (Exception e) {
			// 创建失败
			return false;
		}

	}

	@Override
	protected void waitLock() {
		try {
			IZkDataListener iZkDataListener = new IZkDataListener() {

				public void handleDataDeleted(String path) throws Exception {
					// 唤醒等待线程, 继续往下走.
					if (countDownLatch != null) {
						countDownLatch.countDown();
					}
				}

				public void handleDataChange(String path, Object data) throws Exception {

				}
			};
			// 注册到zk监听中
			zkClient.subscribeDataChanges(PATH, iZkDataListener);
			if (zkClient.exists(PATH)) {
				countDownLatch = new CountDownLatch(1);

				// 等待
				countDownLatch.await();

			}
			// 删除事件通知
			zkClient.unsubscribeDataChanges(PATH, iZkDataListener);
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

}

分布式锁解决思路

分布式锁使用zk,在zk上创建一个临时节点(有效期) ,使用临时节点作为锁,因为节点不允许重复。
如果能创建节点成功,生成订单号,如果创建节点失败,等待。临时节点zk关闭,释放锁,其他节点就可以重新生成订单号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值