package com.lefu.async.disruptor; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.lefu.async.EventData; import com.lefu.async.EventListener; import com.lefu.async.QueueContainer; import com.lefu.async.QueueEvent; import com.lefu.async.support.ThreadPoolFactory; import com.lmax.disruptor.EventFactory; import com.lmax.disruptor.EventTranslatorOneArg; import com.lmax.disruptor.RingBuffer; import com.lmax.disruptor.dsl.Disruptor; /** * 基础队列实现 * @author jiang.li * */ public class DefaultDisruptorQueue implements DisruptorQueue { /** * 默认检查剩余空间大小,应用可以修改这个阀值 */ public static int DEFAULT_CHECK_CAPACITY = 10; private static final String DEFAULT_NAME = "UNKOWN"; private static final EventTranslatorOneArg<QueueEvent, EventData> TRANSLATOR = new DefaultEventDataTranslator(); private final Logger log = LoggerFactory.getLogger(getClass()); private final Disruptor<QueueEvent> disruptor; private RingBuffer<QueueEvent> ringBuffer; private EventTranslatorOneArg<QueueEvent, EventData> translator = TRANSLATOR; private AtomicBoolean isStarted = new AtomicBoolean(false); private String name = DEFAULT_NAME; private int threads = -1; private EventListener eventListener; private boolean logUseTime = false; private QueueContainer queueContainer; private List<String> dependents; private String exceptionQueue; static { try { DEFAULT_CHECK_CAPACITY = Integer.parseInt(System.getProperty("com.lefu.async.defaultCheckSize", "10")); } catch (NumberFormatException e) { } } /** * 使用默认的配置生成指定大小的队列 * @param size */ public DefaultDisruptorQueue(int size) { this(ThreadPoolFactory.EXECUTOR, size); } /** * 使用指定的线程池进行构建 * @param executor * @param size */ public DefaultDisruptorQueue(final Executor executor, int size) { this(new DefaultEventFactory(), executor, size); } /** * 使用指定的事件工厂和线程池进行构建 * @param eventFactory * @param executor * @param size */ public DefaultDisruptorQueue(final EventFactory<QueueEvent> eventFactory, final Executor executor, int size) { this.disruptor = new Disruptor<QueueEvent>(eventFactory, size, executor); } @Override public String getName() { return this.name; } @Override public void start() { if (isStarted.get()) { return; } if (name == null) { throw new NullPointerException("Queue name can not be null"); } if (DEFAULT_NAME.equals(name)) { throw new RuntimeException("You are named queue with default name, you should give it a new unique name"); } if (this.threads <= 0) { throw new RuntimeException("Threads must more than 0"); } if (this.eventListener == null) { throw new RuntimeException("EventListener must be set"); } if (this.queueContainer == null) { throw new RuntimeException("QueueContainer must not be null"); } if (this.dependents != null) { for (String n : dependents) { if (n.equals(name)) { throw new RuntimeException("Queue can not denpend itself"); } } } this.disruptor.handleExceptionsWith(new DefaultExceptionHandler()); ProxyWorkHandler[] handlers = new ProxyWorkHandler[threads]; for (int i = 0; i < threads; i++) { ProxyWorkHandler handler = new ProxyWorkHandler(this.eventListener, getName(), exceptionQueue); handler.setLogUseTime(logUseTime); handler.setDependents(dependents); handlers[i] = handler; } this.disruptor.handleEventsWithWorkerPool(handlers); log.info("Handler listeners with {} thread in queue {}", threads, getName()); this.ringBuffer = this.disruptor.start(); isStarted.set(true); log.info("Queue {} started", getName()); } @Override public void shutdown() { if (!isStarted.get()) { return; } this.disruptor.shutdown(); isStarted.set(false); if (this.eventListener != null) { this.eventListener.destroy(); } log.info("Queue {} shutdown", getName()); } @Override public void publish(EventData data) { this.ringBuffer.publishEvent(translator, data); } @Override public boolean hasAvailableCapacity() { return this.ringBuffer.hasAvailableCapacity(DEFAULT_CHECK_CAPACITY); } @Override public boolean hasDependents() { return this.dependents != null; } @Override public void setThreads(int threads) { this.threads = threads; } @Override public void setEventListener(EventListener eventListener) { this.eventListener = eventListener; } @Override public void setQueueContainer(QueueContainer queueContainer) { this.queueContainer = queueContainer; } public void setTranslator(EventTranslatorOneArg<QueueEvent, EventData> translator) { this.translator = translator; } @Override public void setDependents(List<String> dependents) { this.dependents = dependents; } @Override public void setExceptionQuene(String queueName) { this.exceptionQueue = queueName; } public void setName(String name) { this.name = name; } public void setLogUseTime(boolean logUseTime) { this.logUseTime = logUseTime; } }