跟着RocketMq学源码之锁

本文探讨了RocketMQ Broker中如何通过自旋锁与ReentrantLock在高并发场景下确保消息存储的线程安全。自旋锁通过原子操作减少上下文切换,但可能消耗CPU资源;而ReentrantLock提供可重入性,兼顾效率与公平性。作者还解析了两种锁的实现原理及其适用场景。
摘要由CSDN通过智能技术生成

自旋锁与可重入锁

在RocketMq的broker落盘消息的store代码中,append数据之前加了锁。默认是使用自旋锁。

putMessageLock.lock(); //spin or ReentrantLock ,depending on store config

那么,在mq这种超高并发的情况下,怎么保证线程安全且兼顾效率?

spinlock自旋锁

为什么叫自旋锁呢?

是因为这种获取锁的方式是当一个线程在获取锁时,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁。就像不断的在门口转圈,查看锁开了没。

好处是节省有上下文的切换。坏处是,如果竞争过多,会空耗cpu。

非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入软件内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。(线程被阻塞后便进入内核态,这样导致系统在用户态与内核态之间来回切换,会影响锁的性能)

可以这样理解,内核态相当于一个休息室,非自旋锁发现锁着,就到休息室去了,一会再从休息室过来。自旋锁就一直在门口转悠。

rocketmq中自旋锁的实现,可以拿来参考

public class PutMessageSpinLock {
  //true: 可以获取锁, false : 已经被锁住了.
  private AtomicBoolean putMessageSpinLock = new AtomicBoolean(true);

  @Override
  public void lock() {
      boolean flag;
      do {
          flag = this.putMessageSpinLock.compareAndSet(true, false);
      }
      while (!flag);
  }

  @Override
  public void unlock() {
      this.putMessageSpinLock.compareAndSet(false, true);
  }
}

原理就是不断的尝试compareAndSet,直到set成功。

可以看出这个实现是不可重入的。

ReentrantLock可重入锁

rocketmq直接使用jdk提供的ReentrantLock

ReentrantLock可以根据构造参数选择是公平锁还是非公平锁。非公平锁的优点在于吞吐量比公平锁大。

RocketMq使用的是非公平锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值