共享锁、排他锁

读锁(共享锁)是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。
如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。

写锁(排他锁)如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。

事务可以通过以下语句给sql加共享锁和排他锁:
共享锁:select …… lock in share mode;
不同的事务都可以同时对同一个数据对象进行读操作,而更新操作必须在当前没有任何事务读写操作的情况下进行。

排他锁:select …… for update;
排他锁的核心是如何保证当前有且仅有一个事务获得锁,并且锁被释放后,所有正在等待获取锁的事务都能够被通知到。

共享锁:
适用于两张表存在业务关系时的一致性要求
在这里插入图片描述

排他锁:
适用于操作同一张表时的一致性要求
在这里插入图片描述

羊群效应:多个线程都在zk上注册了自己的顺序临时节点,当xid最小的线程执行完后,释放锁,此时第二个线程获取到锁;但这个过程中,大量的watcher通知和子节点列表获取,这两个操作会重复执行,这样会造成性能影响和网络开销,更严重的是,如果同一时间有多个节点对应的客户端完成事务或事务中断引起节点小的时候,zk服务器短时间内会向所有watch的线程发送大量的事件通知,这就是所谓的羊群效应。

getChildren()不设置Watcher的原因是,防止羊群效应

Watcher 触发条件:

客户端是通过 getData、 getChildren 和 exist 三个接口来向 ZooKeeper 服务器注册 Watcher,且需要多次注册
增、删、改 ( 重复修改也会触发,因为他只告诉你变更了,不告诉你变更多少,需要 客户端 自己去拿)

改进后的分布式锁实现

下面是改进后的分布式锁实现,和之前的实现方式唯一不同之处在于,这里设计成每个锁竞争者,只需要关注”locknode”节点下序号比自己小的那个节点是否存在即可。实现如下:

  1. 客户端调用create()方法创建名为“locknode/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL(临时顺序)。
  2. 客户端调用getChildren(“locknode”)方法来获取所有已经创建的子节点,注意,这里不注册任何Watcher。
  3. 客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点序号最小,那么就认为这个客户端获得了锁。
  4. 如果在步骤3中发现自己并非所有子节点中最小的,说明自己还没有获取到锁。此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时注册事件监听
  5. 之后当这个被关注的节点被移除了,客户端会收到相应的通知。这个时候客户端需要再次调用getChildren(“locknode”)方法来获取所有已经创建的子节点,确保自己确实是最小的节点了,然后进入步骤3。

参考:
mysql写锁:https://blog.csdn.net/u014316026/article/details/78726459
zookeeper实现分布式锁:https://baijiahao.baidu.com/s?id=1610572906386264645&wfr=spider&for=pc

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值