Zookeeper学习笔记(四)分布式锁

一、排他锁与共享锁

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。分为排他锁和共享锁。

排他锁

排他锁(Exclusive Locks, 简称 X 锁),又称为写锁或独占锁,是一种基本的锁类型。如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能再对这个数据对象进行任何类型的操作——直到T1释放了排他锁。

共享锁

共享锁(Shared Locks,简称S锁),又称为读锁。允许一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。(《从PAXOS到ZOOKEEPER分布式一致性原理与实践》中6.17节对共享锁的定义描述实在是不严谨,所以不引用了)。

书上对如何利用Zookeeper实现排他锁和共享锁的描述倒是很清晰易懂的。

对于实现排他锁,简单地说就是多个客户端同时去竞争创建同一个临时子节点,Zookeeper能够保证只有一个客户端创建成功,那么这个创建成功的客户端就获得排他锁。正常情况下,这个客户端执行完业务逻辑会删除这个节点,也就是释放了锁。如果该客户端宕机了,那么这个临时节点会被自动删除,锁也会被释放。

流程图如下:



对于共享锁,则麻烦一些,因为涉及到是读操作还是写操作的问题。所有的客户端都会到某个节点,例如:/shared_lock 下创建一个临时顺序节点,如果是读请求,就会创建诸如 /shared_lock/192.168.0.1-R-0000000001 的节点,如果是写操作,则创建诸如 /shared_lock/192.168.0.1-W-0000000001 的节点。是否获取到共享锁,从以下四个步骤来判断:

1、创建完节点后,获取/shared_lock节点下的所有子节点,并对该节点注册子节点变更的watcher监听。

2、确定自己的节点序号在所有子节点中的顺序。

3、对于读请求:

如果没有比自己序号小的子节点,或是所有比自己序号小的子节点都是去请求,那么表明自己已经成功获取到了共享锁,同时开始执行读取逻辑。

如果比自己序号小的子节点中有写请求,那么就需要进入等待。

对于写请求:

如果自己不是序号最小的子节点,那么就需要进入等待。

4、接收到Watcher通知后,重复步骤1。

流程图如下:



二、排他锁的Curator实现

基本摘抄自书上的示例代码:

package com.my.CuratorTest;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.concurrent.CountDownLatch;

/**
 * Title: <br/>
 * Intention: <br/>
 * <p>
 * Class Name: com.my.CuratorTest.RecipesSharedLockTest<br/>
 * Create Date: 2017/8/20 17:07 <br/>
 * Project Name: MyTest <br/>
 * Company:  All Rights Reserved. <br/>
 * Copyright © 2017 <br/>
 * </p>
 * <p>
 * author: GaoWei <br/>
 * 1st_examiner: <br/>
 * 2nd_examiner: <br/>
 * </p>
 *
 * @version 1.0
 * @since JDK 1.7
 */
public class RecipesSharedLockTest {

	static String lockPath = "/curator_recipes_lock_path";

	static CuratorFramework client = CuratorFrameworkFactory.builder()
			.connectString("127.0.0.1:2181")
			.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();


	static int data = 1;

	public static void main(String[] args) {
		client.start();
		final InterProcessReadWriteLock lock = new InterProcessReadWriteLock(client, lockPath);
		final CountDownLatch down = new CountDownLatch(1);
		for (int i= 0;i< 30;i++) {
			final int k = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					if (k%2 == 0) {
						try {
							down.countDown();
							lock.readLock().acquire();
							System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到读锁,当前数据="+ data);
							lock.readLock().release();
						} catch (Exception e) {
							e.printStackTrace();
						}
					} else {
						try {
							down.countDown();
							lock.writeLock().acquire();
							data ++;
							System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到写锁,写入成功,当前数据="+ data);
							lock.writeLock().release();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
		}
		down.countDown();
	}
}


三、共享锁的Curator实现

package com.my.CuratorTest;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.concurrent.CountDownLatch;

/**
 * Title: <br/>
 * Intention: <br/>
 * <p>
 * Class Name: com.my.CuratorTest.RecipesSharedLockTest<br/>
 * Create Date: 2017/8/20 17:07 <br/>
 * Project Name: MyTest <br/>
 * Company:  All Rights Reserved. <br/>
 * Copyright © 2017 <br/>
 * </p>
 * <p>
 * author: GaoWei <br/>
 * 1st_examiner: <br/>
 * 2nd_examiner: <br/>
 * </p>
 *
 * @version 1.0
 * @since JDK 1.7
 */
public class RecipesSharedLockTest {

	static String lockPath = "/curator_recipes_lock_path";

	static CuratorFramework client = CuratorFrameworkFactory.builder()
			.connectString("127.0.0.1:2181")
			.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();


	static int data = 1;

	public static void main(String[] args) {
		client.start();
		final InterProcessReadWriteLock lock = new InterProcessReadWriteLock(client, lockPath);
		final CountDownLatch down = new CountDownLatch(1);
		for (int i= 0;i< 30;i++) {
			final int k = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					if (k%2 == 0) {
						try {
							down.countDown();
							lock.readLock().acquire();
							System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到读锁,当前数据="+ data);
							lock.readLock().release();
						} catch (Exception e) {
							e.printStackTrace();
						}
					} else {
						try {
							down.countDown();
							lock.writeLock().acquire();
							data ++;
							System.out.println(System.nanoTime() + ", " + Thread.currentThread().getName() + " 获取到写锁,写入成功,当前数据="+ data);
							lock.writeLock().release();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
		}
		down.countDown();
	}
}


参考:

1、从PAXOS到ZOOKEEPER分布式一致性原理与实践

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值