**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
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();
}
}
生产者对象:
public class OrderEventProducer {
//事件队列
private RingBuffer<OrderEvent> ringBuffer;
public OrderEventProducer(RingBuffer<OrderEvent> ringBuffer) {
this.ringBuffer = ringBuffer;
}
public void onData(long value,String name) {
// 获取事件队列 的下一个槽
long sequence = ringBuffer.next();
try {
//获取消息(事件)
OrderEvent orderEvent = ringBuffer.get(sequence);
// 写入消息数据
orderEvent.setValue(value);
orderEvent.setName(name);
} catch (Exception e) {
// TODO 异常处理
e.printStackTrace();
} finally {
System.out.println("生产者"+ Thread.currentThread().getName()
+"发送数据value:"+value+",name:"+name);
//发布事件
ringBuffer.publish(sequence);
}
}
}
构造方法:
/**
* Create a new Disruptor.
*
* @param eventFactory the factory to create events in the ring buffer.
* @param ringBufferSize the size of the ring buffer, must be power of 2.
* @param threadFactory a {@link ThreadFactory} to create threads for processors.
* @param producerType the claim strategy to use for the ring buffer.
* @param waitStrategy the wait strategy to use for the ring buffer.
*/
public Disruptor(
final EventFactory<T> eventFactory,
final int ringBufferSize,
final ThreadFactory threadFactory,
final ProducerType producerType,
final WaitStrategy waitStrategy)
{
this(
RingBuffer.create(producerType, eventFactory, ringBufferSize, waitStrategy),
new BasicExecutor(threadFactory));
}
BasicExecutor构造方法:
public BasicExecutor(ThreadFactory factory)
{
this.factory = factory;
}
BasicExecutor属性:
private final ThreadFactory factory;
private final Queue<Thread> threads = new ConcurrentLinkedQueue<>();
BasicExecutor的execute方法:
@Override
public void execute(Runnable command)
{
final Thread thread = factory.newThread(command);
if (null == thread)
{
throw new RuntimeException("Failed to create thread to run: " + command);
}
thread.start();
threads.add(thread);
}
执行任务的时候,会把新创建的线程存入一个队列中.
BasicExecutor的dumpThreadInfo方法:
private String dumpThreadInfo()
{
final StringBuilder sb = new StringBuilder();
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
for (Thread t : threads)
{
ThreadInfo threadInfo = threadMXBean.getThreadInfo(t.getId());
sb.append("{");
sb.append("name=").append(t.getName()).append(",");
sb.append("id=").append(t.getId()).append(",");
sb.append("state=").append(threadInfo.getThreadState()).append(",");
sb.append("lockInfo=").append(threadInfo.getLockInfo());
sb.append("}");
}
return sb.toString();
}
会通过遍历来把执行任务的线程信息打印出来.
RingBuffer的create方法:
/**
* Create a new Ring Buffer with the specified producer type (SINGLE or MULTI)
*
* @param <E> Class of the event stored in the ring buffer.
* @param producerType producer type to use {@link ProducerType}.
* @param factory used to create 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
*/
public static <E> RingBuffer<E> create(
ProducerType producerType,
EventFactory<E> factory,
int bufferSize,
WaitStrategy waitStrategy)
{
switch (producerType)
{
case SINGLE:
return createSingleProducer(factory, bufferSize, waitStrategy);
case MULTI:
return createMultiProducer(factory, bufferSize, waitStrategy);
default:
throw new IllegalStateException(producerType.toString());
}
}
RingBuffer的create方法理解:
因为是一个抽象类,所以需要一个具体的实现,抽象类的目的只是为了把共性实现抽出来.
createSingleProducer方法:
/**
* Create a new single 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 SingleProducerSequencer
*/
public static <E> RingBuffer<E> createSingleProducer(
EventFactory<E> factory,
int bufferSize,
WaitStrategy waitStrategy)
{
SingleProducerSequencer sequencer = new SingleProducerSequencer(bufferSize, waitStrategy);
return new RingBuffer<E>(factory, sequencer);
}
createSingleProducer方法理解:
父类构造方法的实现.
newRingBuffer方法:
/**
* Construct a RingBuffer with the full option set.
*
* @param eventFactory to newInstance entries for filling the RingBuffer
* @param sequencer sequencer to handle the ordering of events moving through the RingBuffer.
* @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
*/
RingBuffer(
EventFactory<E> eventFactory,
Sequencer sequencer)
{
super(eventFactory, sequencer);
}
RingBufferFields(
EventFactory<E> eventFactory,
Sequencer sequencer)
{
this.sequencer = sequencer;
this.bufferSize = sequencer.getBufferSize();
if (bufferSize < 1)
{
throw new IllegalArgumentException("bufferSize must not be less than 1");
}
if (Integer.bitCount(bufferSize) != 1)
{
throw new IllegalArgumentException("bufferSize must be a power of 2");
}
this.indexMask = bufferSize - 1;
this.entries = new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];
fill(eventFactory);
}
构造方法理解:
fill方法:
private void fill(EventFactory<E> eventFactory)
{
for (int i = 0; i < bufferSize; i++)
{
entries[BUFFER_PAD + i] = eventFactory.newInstance();
}
}
把数组里都放入构造方法传入的生产者对象.
createMultiProducer方法:
/**
* 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);
}
createMultiProducer方法理解:
缓冲区的值都设置为了-1.
启动方法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理解:
生产者onData方法:
ringBuffer的next方法:
/**
* Increment and return the next sequence for the ring buffer. Calls of this
* method should ensure that they always publish the sequence afterward. E.g.
* <pre>
* long sequence = ringBuffer.next();
* try {
* Event e = ringBuffer.get(sequence);
* // Do some work with the event.
* } finally {
* ringBuffer.publish(sequence);
* }
* </pre>
*
* @return The next sequence to publish to.
* @see RingBuffer#publish(long)
* @see RingBuffer#get(long)
*/
@Override
public long next()
{
return sequencer.next();
}
sequencer的next方法:
因为是个接口,先看单生产者实现.
@Override
public long next()
{
return next(1);
}
/**
* @see Sequencer#next(int)
*/
@Override
public long next(int n)
{
if (n < 1)
{
throw new IllegalArgumentException("n must be > 0");
}
long nextValue = this.nextValue;
long nextSequence = nextValue + n;
long wrapPoint = nextSequence - bufferSize;
long cachedGatingSequence = this.cachedValue;
if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue)
{
cursor.setVolatile(nextValue); // StoreLoad fence
long minSequence;
while (wrapPoint > (minSequence = Util.getMinimumSequence(gatingSequences, nextValue)))
{
LockSupport.parkNanos(1L); // TODO: Use waitStrategy to spin?
}
this.cachedValue = minSequence;
}
this.nextValue = nextSequence;
return nextSequence;
}
sequencer的next方法理解:
getMinimumSequence方法:
/**
* Get the minimum sequence from an array of {@link com.lmax.disruptor.Sequence}s.
*
* @param sequences to compare.
* @param minimum an initial default minimum. If the array is empty this value will be
* returned.
* @return the smaller of minimum sequence value found in {@code sequences} and {@code minimum};
* {@code minimum} if {@code sequences} is empty
*/
public static long getMinimumSequence(final Sequence[] sequences, long minimum)
{
for (int i = 0, n = sequences.length; i < n; i++)
{
long value = sequences[i].get();
minimum = Math.min(minimum, value);
}
return minimum;
}
getMinimumSequence方法理解:
具体什么时候满足条件进入.我还没想明白.等后续看其他例子的分析是不是会找到答案.
ringBuffer的get方法:
/**
* <p>Get the event for a given sequence in the RingBuffer.</p>
*
* <p>This call has 2 uses. Firstly use this call when publishing to a ring buffer.
* After calling {@link RingBuffer#next()} use this call to get hold of the
* preallocated event to fill with data before calling {@link RingBuffer#publish(long)}.</p>
*
* <p>Secondly use this call when consuming data from the ring buffer. After calling
* {@link SequenceBarrier#waitFor(long)} call this method with any value greater than
* that your current consumer sequence and less than or equal to the value returned from
* the {@link SequenceBarrier#waitFor(long)} method.</p>
*
* @param sequence for the event
* @return the event for the given sequence
*/
@Override
public E get(long sequence)
{
return elementAt(sequence);
}
protected final E elementAt(long sequence)
{
return (E) UNSAFE.getObject(entries, REF_ARRAY_BASE + ((sequence & indexMask) << REF_ELEMENT_SHIFT));
}
ringBuffer的get方法理解:
重要的不是源码本身,而是背后的思路.
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();
}
这就是Disruptor生产者源码的一个思路.前面有一篇文章有一些简单的应用,依赖.
下面还会继续学习分析消费多消费策略等源码.