Java 无锁队列 Disruptor,内存队列的生产解决方案

背景

Disruptor是英国外汇交易所LMAX开源的用于生产交易中的内存队列。

为了实现高性能交易撮合队列时,现在普遍的交易撮合引擎都采用了内存队列的方式,这种方式减少了持久化过程中带来的磁盘IO延迟,可以提交整体的交易性能。

Disruptor便是这样场景中诞生的,在实际使用过程中,LMAX基于Disruptor开发的系统单线程能支撑每秒600万订单。

Java队列

内存队列通常用于内存共享场景下的,而共享内存与锁有必然分不开的情缘,在java内置的线程安全的队列有以下:

队列 有界性 数据结构
ArrayBlockingQueue bounded 加锁 arraylist
LinkedBlockingQueue optionally-bounded 加锁 linkedlist
ConcurrentLinkedQueue unbounded 无锁 linkedlist
LinkedTransferQueue unbounded 无锁 linkedlist
PriorityBlockingQueue unbounded 加锁 heap
DelayQueue unbounded 加锁 heap

ConcurrentLinkedQueue以及LinkedTransferQueue的无锁都是通过原子变量compare and swap(以下简称“CAS”)操作的。

为什么要无锁

现实编程过程中,加锁通常会严重地影响性能。线程会因为竞争不到锁而被挂起,等锁被释放的时候,线程又会被恢复,这个过程中存在着很大的开销,并且通常会有较长时间的中断,因为当一个线程正在等待锁时,它不能做任何其他事情。如果一个线程在持有锁的情况下被延迟执行,例如发生了缺页错误、调度延迟或者其它类似情况,那么所有需要这个锁的线程都无法执行下去。如果被阻塞线程的优先级较高,而持有锁的线程优先级较低,就会发生优先级反转。

Disruptor论文中讲述了一个实验:

这个测试程序调用了一个函数,该函数会对一个64位的计数器循环自增5亿次。
机器环境:2.4G 6核
运算: 64位的计数器累加5亿次
其测试结果:

Method Time (ms)
Single thread 300
Single thread with CAS 5,700
Single thread with lock 10,000
Single thread with volatile write 4,700
Two threads with CAS 30,000
Two threads with lock 224,000

实际开发过的应该也知道这个结论:不加锁是最快的。

虽然知道无锁最快,但是我们核心还是要解决地是共享数据多线程安全访问呀(单线程能处理那么单线程最好了,不如actor模型,每个actor就是一个独占线程,反正永不停歇,那就没必要线程切换,保证效能)。

下面是ArrayBlockingQueue通过加锁的方式实现的offer方法,保证线程安全。

public boolean offer(E e) {
   
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
   
        if (count == items.length)
            return false;
        else {
   
            insert(e);
            return 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值