juc下的队列大部分采用加ReentrantLock锁方式保证线程安全.在稳定性要求特别高的系统中,为了防止生产者速度过快,导致内存溢出,只能选择有界队列.加锁的方式通常会严重影响性能。线程会因为竞争不到锁而被挂起,等待其他线程释放锁而唤醒,这个过程存在很大的开销,而且存在死锁的隐患。
分析demo:
scss
public class DisruptorDemo{
public static void main(String[] args) throws Exception {
//创建disruptor
Disruptor<OrderEvent> disruptor = new Disruptor<>(
new OrderEventFactory(),
64,
Executors.defaultThreadFactory(),
//多生产者
ProducerType.MULTI,
//等待策略
new YieldingWaitStrategy()
);
//设置多消费者,消费者要实现WorkHandler接口,一条消息只会被一个消费者消费
disruptor.handleEventsWithWorkerPool(new OrderEventHandler(), new OrderEventHandler());
//启动disruptor
disruptor.start();
//创建ringbuffer容器
RingBuffer<OrderEvent> ringBuffer = disruptor.getRingBuffer();
new Thread(()->{
//创建生产者
OrderEventProducer eventProducer = new OrderEventProducer(ringBuffer);
// 发送消息
for(int i=0;i<5;i++){
eventProducer.onData(i,"producer1--"+i);
}
},"producer1").start();
new Thread(()->{
//创建生产者
OrderEventProducer eventProducer = new OrderEventProducer(ringBuffer);
// 发送消息
for(int i=0;i<5;i++){
eventProducer.onData(i,"producer2--"+i);
}
},"producer2").start();
Thread.sleep(10000);
disruptor.shutdown();
}
}
生产者:
csharp
public class OrderEventHandler implements WorkHandler<OrderEvent> {
@Override
public void onEvent(OrderEvent event) throws Exception {
// TODO 消费逻辑
System.out.println("消费者"+ Thread.currentThread().getName()
+"获取数据value:"+ event.getValue()+",name:"+event.getName());
}
}
运行结果:

从结果可以看出消费者只消费一次消息,不会重复消费.
理解:

所以构造方法内部的用的是multiProducer.直接进入关键.
createMultiProducer方法:
java
/**
* Create a new multiple producer RingBuffer with the specified wait strategy.
*
* @param <E> Class of the event stored in the ring buffer.
* @param factory used to create the events within the ring buffer.
* @param bufferSize number of elements to create within the ring buffer.
* @param waitStrategy used to determine how to wait for new elements to become available.
* @return a constructed ring buffer.
* @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
* @see MultiProducerSequencer
*/
public static <E> RingBuffer<E> createMultiProducer(
EventFactory<E> factory,
int bufferSize,
WaitStrategy waitStrategy)
{
MultiProducerSequencer sequencer = new MultiProducerSequencer(bufferSize, waitStrategy);
return new RingBuffer<E>(factory, sequencer);
}
MultiProducerSequencer方法:
scss
/**
* Construct a Sequencer with the selected wait strategy and buffer size.
*
* @param bufferSize the size of the buffer that this will sequence over.
* @param waitStrategy for those waiting on sequences.
*/
public MultiProducerSequencer(int bufferSize, final WaitStrategy waitStrategy)
{
super(bufferSize, waitStrategy);
availableBuffer = new int[bufferSize];
indexMask = bufferSize - 1;
indexShift = Util.log2(bufferSize);
initialiseAvailableBuffer();
}
initialiseAvailableBuffer方法:
scss
private void initialiseAvailableBuffer()
{
for (int i = availableBuffer.length - 1; i != 0; i--)
{
setAvailableBufferValue(i, -1);
}
setAvailableBufferValue(0, -1);
}
initialiseAvailableBuffer方法理解:
遍历把数组的值都设置为-1.
多生产者和单生产者类似,可以参考前面的文章.
handleEventsWithWorkerPool方法:
less
/**
* Set up a {@link WorkerPool} to distribute an event to one of a pool of work handler threads.
* Each event will only be processed by one of the work handlers.
* The Disruptor will automatically start this processors when {@link #start()} is called.
*
* @param workHandlers the work handlers that will process events.
* @return a {@link EventHandlerGroup} that can be used to chain dependencies.
*/
@SafeVarargs
@SuppressWarnings("varargs")
public final EventHandlerGroup<T> handleEventsWithWorkerPool(final WorkHandler<T>... workHandlers)
{
return createWorkerPool(new Sequence[0], workHandlers);
}
createWorkerPool方法:
ini
EventHandlerGroup<T> createWorkerPool(
final Sequence[] barrierSequences, final WorkHandler<? super T>[] workHandlers)
{
final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(barrierSequences);
final WorkerPool<T> workerPool = new WorkerPool<>(ringBuffer, sequenceBarrier, exceptionHandler, workHandlers);
consumerRepository.add(workerPool, sequenceBarrier);
final Sequence[] workerSequences = workerPool.getWorkerSequences();
updateGatingSequencesForNextInChain(barrierSequences, workerSequences);
return new EventHandlerGroup<>(this, consumerRepository, workerSequences);
}
createWorkerPool方法理解:

workPool构造方法:
java
/**
* Create a worker pool to enable an array of {@link WorkHandler}s to consume published sequences.
* <p>
* This option requires a pre-configured {@link RingBuffer} which must have {@link RingBuffer#addGatingSequences(Sequence...)}
* called before the work pool is started.
*
* @param ringBuffer of events to be consumed.
* @param sequenceBarrier on which the workers will depend.
* @param exceptionHandler to callback when an error occurs which is not handled by the {@link WorkHandler}s.
* @param workHandlers to distribute the work load across.
*/
@SafeVarargs
public WorkerPool(
final RingBuffer<T> ringBuffer,
final SequenceBarrier sequenceBarrier,
final ExceptionHandler<? super T> exceptionHandler,
final WorkHandler<? super T>... workHandlers)
{
this.ringBuffer = ringBuffer;
final int numWorkers = workHandlers.length;
workProcessors = new WorkProcessor[numWorkers];
for (int i = 0; i < numWorkers; i++)
{
workProcessors[i] = new WorkProcessor<>(
ringBuffer,
sequenceBarrier,
workHandlers[i],
exceptionHandler,
workSequence);
}
}
workPool构造方法理解:

add方法:
arduino
public void add(final WorkerPool<T> workerPool, final SequenceBarrier sequenceBarrier)
{
final WorkerPoolInfo<T> workerPoolInfo = new WorkerPoolInfo<>(workerPool, sequenceBarrier);
consumerInfos.add(workerPoolInfo);
for (Sequence sequence : workerPool.getWorkerSequences())
{
eventProcessorInfoBySequence.put(sequence, workerPoolInfo);
}
}
add方法理解:

start方法:
scss
/**
* <p>Starts the event processors and returns the fully configured ring buffer.</p>
*
* <p>The ring buffer is set up to prevent overwriting any entry that is yet to
* be processed by the slowest event processor.</p>
*
* <p>This method must only be called once after all event processors have been added.</p>
*
* @return the configured ring buffer.
*/
public RingBuffer<T> start()
{
checkOnlyStartedOnce();
for (final ConsumerInfo consumerInfo : consumerRepository)
{
consumerInfo.start(executor);
}
return ringBuffer;
}
start方法理解:


start方法:
typescript
@Override
public void start(Executor executor)
{
workerPool.start(executor);
}
然后又继续调用了workPool的start方法.
arduino
/**
* Start the worker pool processing events in sequence.
*
* @param executor providing threads for running the workers.
* @return the {@link RingBuffer} used for the work queue.
* @throws IllegalStateException if the pool has already been started and not halted yet
*/
public RingBuffer<T> start(final Executor executor)
{
if (!started.compareAndSet(false, true))
{
throw new IllegalStateException("WorkerPool has already been started and cannot be restarted until halted.");
}
final long cursor = ringBuffer.getCursor();
workSequence.set(cursor);
for (WorkProcessor<?> processor : workProcessors)
{
processor.getSequence().set(cursor);
executor.execute(processor);
}
return ringBuffer;
}
workPool的start方法理解:

workProcessor的run方法:
csharp
/**
* It is ok to have another thread re-run this method after a halt().
*
* @throws IllegalStateException if this processor is already running
*/
@Override
public void run()
{
if (!running.compareAndSet(false, true))
{
throw new IllegalStateException("Thread is already running");
}
sequenceBarrier.clearAlert();
notifyStart();
boolean processedSequence = true;
long cachedAvailableSequence = Long.MIN_VALUE;
long nextSequence = sequence.get();
T event = null;
while (true)
{
try
{
// if previous sequence was processed - fetch the next sequence and set
// that we have successfully processed the previous sequence
// typically, this will be true
// this prevents the sequence getting too far forward if an exception
// is thrown from the WorkHandler
if (processedSequence)
{
processedSequence = false;
do
{
nextSequence = workSequence.get() + 1L;
sequence.set(nextSequence - 1L);
}
while (!workSequence.compareAndSet(nextSequence - 1L, nextSequence));
}
if (cachedAvailableSequence >= nextSequence)
{
event = ringBuffer.get(nextSequence);
workHandler.onEvent(event);
processedSequence = true;
}
else
{
cachedAvailableSequence = sequenceBarrier.waitFor(nextSequence);
}
}
catch (final TimeoutException e)
{
notifyTimeout(sequence.get());
}
catch (final AlertException ex)
{
if (!running.get())
{
break;
}
}
catch (final Throwable ex)
{
// handle, mark as processed, unless the exception handler threw an exception
exceptionHandler.handleEventException(ex, nextSequence, event);
processedSequence = true;
}
}
notifyShutdown();
running.set(false);
}
workProcessor的run方法理解:

通过断点可以看出多消费者是共享屏障和缓冲区达到不重复消费的结果.通过cas操作保证了线程安全.


发布方法,可以参考前面单消费者的逻辑.
语雀地址www.yuque.com/itbosunmian...?
《Go.》 密码:xbkk 欢迎大家访问.提意见.