juc下的队列大部分采用加ReentrantLock锁方式保证线程安全.在稳定性要求特别高的系统中,为了防止生产者速度过快,导致内存溢出,只能选择有界队列.加锁的方式通常会严重影响性能。线程会因为竞争不到锁而被挂起,等待其他线程释放锁而唤醒,这个过程存在很大的开销,而且存在死锁的隐患。
分析demo:
public class DisruptorDemo {
public static void main(String[] args) throws Exception {
//创建disruptor
Disruptor<OrderEvent> disruptor = new Disruptor<>(
OrderEvent::new,
//缓冲区大小,要为2的n次方.
4,
Executors.defaultThreadFactory(),
//单生产者
ProducerType.SINGLE,
//等待策略
new YieldingWaitStrategy()
);
//设置消费者
disruptor.handleEventsWith(new OrderEventHandler());
//启动disruptor
disruptor.start();
//创建ringbuffer容器
RingBuffer<OrderEvent> ringBuffer = disruptor.getRingBuffer();
//创建生产者
OrderEventProducer eventProducer = new OrderEventProducer(ringBuffer);
// 发送消息
for (int i = 0; i < 10; i++) {
eventProducer.onData(i, "Disruptor" + i);
}
disruptor.shutdown();
}
}
handleEventsWith方法是可以注册多个消费者的.但是会重复消费.等会我们看源码的时候就可以知道.
消费者demo:
public class OrderEventHandler implements EventHandler<OrderEvent> {
@Override
public void onEvent(OrderEvent event, long sequence, boolean endOfBatch) throws Exception {
// TODO 消费逻辑
System.out.println("消费者"+ Thread.currentThread().getName()
+"获取数据value:"+ event.getValue()+",name:"+event.getName());
}
}
消费者需要实现EventHandler接口的onEvent方法来完成消费逻辑.
执行结果:
前面已经有文章介绍生产逻辑了.这里就重点介绍消费者逻辑了.
消费注册handleEventsWith方法:
/**
* <p>Set up event handlers to handle events from the ring buffer. These handlers will process events
* as soon as they become available, in parallel.</p>
*
* <p>This method can be used as the start of a chain. For example if the handler <code>A</code> must
* process events before handler <code>B</code>:</p>
* <pre><code>dw.handleEventsWith(A).then(B);</code></pre>
*
* <p>This call is additive, but generally should only be called once when setting up the Disruptor instance</p>
*
* @param handlers the event handlers that will process events.
* @return a {@link EventHandlerGroup} that can be used to chain dependencies.
*/
@SuppressWarnings("varargs")
@SafeVarargs
public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)
{
return createEventProcessors(new Sequence[0], handlers);
}
消费注册handleEventsWith方法理解:
createEventProcessors方法:
EventHandlerGroup<T> createEventProcessors(
final Sequence[] barrierSequences,
final EventHandler<? super T>[] eventHandlers)
{
checkNotStarted();
final Sequence[] processorSequences = new Sequence[eventHandlers.length];
final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);
for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++)
{
final EventHandler<? super T> eventHandler = eventHandlers[i];
final BatchEventProcessor<T> batchEventProcessor =
new BatchEventProcessor<>(ringBuffer, barrier, eventHandler);
if (exceptionHandler != null)
{
batchEventProcessor.setExceptionHandler(exceptionHandler);
}
consumerRepository.add(batchEventProcessor, eventHandler, barrier);
processorSequences[i] = batchEventProcessor.getSequence();
}
updateGatingSequencesForNextInChain(barrierSequences, processorSequences);
return new EventHandlerGroup<>(this, consumerRepository, processorSequences);
}
createEventProcessors方法理解:
1.checkNotStarted方法:
private void checkNotStarted()
{
if (started.get())
{
throw new IllegalStateException("All event handlers must be added before calling starts.");
}
}
从报错的提示可以看出,所有的消费逻辑应该在启动之前.
2.
ringBuffer的newBarrier方法:
/**
* Create a new SequenceBarrier to be used by an EventProcessor to track which messages
* are available to be read from the ring buffer given a list of sequences to track.
*
* @param sequencesToTrack the additional sequences to track
* @return A sequence barrier that will track the specified sequences.
* @see SequenceBarrier
*/
public SequenceBarrier newBarrier(Sequence... sequencesToTrack)
{
return sequencer.newBarrier(sequencesToTrack);
}
/**
* @see Sequencer#newBarrier(Sequence...)
*/
@Override
public SequenceBarrier newBarrier(Sequence... sequencesToTrack)
{
return new ProcessingSequenceBarrier(this, waitStrategy, cursor, sequencesToTrack);
}
ProcessingSequenceBarrier构造方法:
ProcessingSequenceBarrier(
final Sequencer sequencer,
final WaitStrategy waitStrategy,
final Sequence cursorSequence,
final Sequence[] dependentSequences)
{
this.sequencer = sequencer;
this.waitStrategy = waitStrategy;
this.cursorSequence = cursorSequence;
if (0 == dependentSequences.length)
{
dependentSequence = cursorSequence;
}
else
{
dependentSequence = new FixedSequenceGroup(dependentSequences);
}
}
ProcessingSequenceBarrier构造方法理解:
到这里这个屏障对象就创建好了.
4.BatchEventProcessor理解:
这个类实现了EventProcessor接口,EventProcessor接口又实现了Runnable接口.可以猜测到最后需要线程来执行这个任务.(构造方法就不往出贴了,好奇的话,可以点击去看看.)
5.consumerRepository的add方法:
public void add(
final EventProcessor eventprocessor,
final EventHandler<? super T> handler,
final SequenceBarrier barrier)
{
final EventProcessorInfo<T> consumerInfo = new EventProcessorInfo<>(eventprocessor, handler, barrier);
eventProcessorInfoByEventHandler.put(handler, consumerInfo);
eventProcessorInfoBySequence.put(eventprocessor.getSequence(), consumerInfo);
consumerInfos.add(consumerInfo);
}
这个方法把handler包装为EventProcessorInfo并且实现了ConsumerInfo接口.ConsumerRepository实现了迭代器可以进行for循环,后面启动可以看到使用了for循环.
到此为止我们的消费逻辑的注册就已经结束了.剩下的就是启动了.
启动方法start:
/**
* <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方法理解:
consumerInfo的start方法:
@Override
public void start(final Executor executor)
{
executor.execute(eventprocessor);
}
看到excute,直接找run方法.因为前面已经介绍了,消费逻辑包装成了BatchEventProcessor对象,所以直接进入这个对象找run方法.
/**
* It is ok to have another thread rerun this method after a halt().
*
* @throws IllegalStateException if this object instance is already running in a thread
*/
@Override
public void run()
{
if (running.compareAndSet(IDLE, RUNNING))
{
sequenceBarrier.clearAlert();
notifyStart();
try
{
if (running.get() == RUNNING)
{
processEvents();
}
}
finally
{
notifyShutdown();
running.set(IDLE);
}
}
else
{
// This is a little bit of guess work. The running state could of changed to HALTED by
// this point. However, Java does not have compareAndExchange which is the only way
// to get it exactly correct.
if (running.get() == RUNNING)
{
throw new IllegalStateException("Thread is already running");
}
else
{
earlyExit();
}
}
}
run方法理解:
processEvents方法:
private void processEvents()
{
T event = null;
long nextSequence = sequence.get() + 1L;
while (true)
{
try
{
final long availableSequence = sequenceBarrier.waitFor(nextSequence);
if (batchStartAware != null)
{
batchStartAware.onBatchStart(availableSequence - nextSequence + 1);
}
while (nextSequence <= availableSequence)
{
event = dataProvider.get(nextSequence);
eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
nextSequence++;
}
sequence.set(availableSequence);
}
catch (final TimeoutException e)
{
notifyTimeout(sequence.get());
}
catch (final AlertException ex)
{
if (running.get() != RUNNING)
{
break;
}
}
catch (final Throwable ex)
{
exceptionHandler.handleEventException(ex, nextSequence, event);
sequence.set(nextSequence);
nextSequence++;
}
}
}
processEvents方法理解:
消费类实现了eventHandler接口的onEvent方法.所以最终会调用到.
waitFor方法:
@Override
public long waitFor(final long sequence)
throws AlertException, InterruptedException, TimeoutException
{
checkAlert();
long availableSequence = waitStrategy.waitFor(sequence, cursorSequence, dependentSequence, this);
if (availableSequence < sequence)
{
return availableSequence;
}
return sequencer.getHighestPublishedSequence(sequence, availableSequence);
}
等待策略的waitFor方法:
@Override
public long waitFor(
final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)
throws AlertException, InterruptedException
{
long availableSequence;
int counter = SPIN_TRIES;
while ((availableSequence = dependentSequence.get()) < sequence)
{
counter = applyWaitMethod(barrier, counter);
}
return availableSequence;
}
这里我们看的是yielding这个策略实现.
等待策略的waitFor方法理解:
applyWaitMethod方法:
private int applyWaitMethod(final SequenceBarrier barrier, int counter)
throws AlertException
{
barrier.checkAlert();
if (0 == counter)
{
Thread.yield();
}
else
{
--counter;
}
return counter;
}
如果不满足条件.counter会一直减1,counter的值为100,如果等于0还不满足,就会通过yield让出cpu执行时间片,来达到阻塞的目的.
这就是启动消费者的流程.
ringBuffer的publish方法:
/**
* Publish the specified sequence. This action marks this particular
* message as being available to be read.
*
* @param sequence the sequence to publish.
*/
@Override
public void publish(long sequence)
{
sequencer.publish(sequence);
}
/**
* @see Sequencer#publish(long)
*/
@Override
public void publish(long sequence)
{
cursor.set(sequence);
waitStrategy.signalAllWhenBlocking();
}
publish方法理解:
空说无凭,上断点验证.
从断点能看出来,发布设置成功后,消费者任务就会跳出循环,执行消费逻辑.