先看看ArrayBlockingQueue的源码,主要有两个方法
先看put方法:向队列的尾部插入元素,若已满则等待。
/** * Inserts the specified element at the tail of this queue, waiting * for space to become available if the queue is full. * * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == items.length) notFull.await(); enqueue(e); } finally { lock.unlock(); } }
/** * Inserts element at current put position, advances, and signals. * Call only when holding lock. */ private void enqueue(E x) { // assert lock.getHoldCount() == 1; // assert items[putIndex] == null; final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length) putIndex = 0; count++; notEmpty.signal(); }
再看take方法: 从队列的头部消费元素,若已空则等待。
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return dequeue(); } finally { lock.unlock(); } }
/** * Extracts element at current take position, advances, and signals. * Call only when holding lock. */ private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] != null; final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); notFull.signal(); return x; }
ArrayBlockingQueue 性能瓶颈在于,put和take都需要获取同一个锁,不能两头并发。
/* * Concurrency control uses the classic two-condition algorithm * found in any textbook. */ /** Main lock guarding all access */ final ReentrantLock lock;
看看LMAX Disruptor的改进:
1)使用CAS进行sequence获取,相当于存放元素的index获取,仅在这里并发控制。
2)false sharing of cash line, sequence 进行padding 防止false sharing.
3) 使用memory fence publish event,让其他线程可以看到更新后的event,减少并发控制。
参考:
https://itnext.io/understanding-the-lmax-disruptor-caaaa2721496
https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started