在这种高并发多线程的情况下,解决问题最有效最普遍的方法就是给共享资源或对共享资源的操作加一把锁,来保证对资源的访问互斥。在Java JDK已经为我们提供了这样的锁,利用ReentrantLcok或者synchronized,即可达到资源互斥访问的目的。但是在分布式系统中,由于分布式系统的分布性,即多线程和多进程并且分布在不同机器中,这两种锁将失去原有锁的效果,需要我们自己实现分布式锁——分布式锁。
zookeeper分布式锁
zookeeper分布式锁
首先我们来了解一下zookeeper的特性,看看它为什么适合做分布式锁,
zookeeper是一个为分布式应用提供一致性服务的软件,它内部是一个分层的文件系统目录树结构,规定统一个目录下只能有一个唯一文件名。
数据模型:
-
永久节点:节点创建后,不会因为会话失效而消失
-
临时节点:与永久节点相反,如果客户端连接失效,则立即删除节点
-
顺序节点:与上述两个节点特性类似,如果指定创建这类节点时,zk会自动在节点名后加一个数字后缀,并且是有序的。
监视器(watcher):
-
当创建一个节点时,可以注册一个该节点的监视器,当节点状态发生改变时,watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次。
根据zookeeper的这些特性,我们来看看如何利用这些特性来实现分布式锁:
1. 创建一个锁目录lock
2. 希望获得锁的线程A就在lock目录下,创建临时顺序节点
3. 获取锁目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁
4. 线程B获取所有节点,判断自己不是最小节点,设置监听(watcher)比自己次小的节点(只关注比自己次小的节点是为了防止发生“羊群效应”)
5. 线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是最小的节点,获得锁。