前言:这一章东西,可能突然有点多,我还特意少些了一点,免得东西太多,大家混乱了。本来很多东西我可以把源码那里搬过来,但我想想,这样就缺少了手撕的感觉。有可能我没搬过来,读者再去看源码就会发现原来,那样写会更好。多一点思考,比什么都重要,虽然是手撕,但我也希望读者是带着思考去想的。而且我这些手撕是基于单线程的。单的手撕完之后,我们再继续增加一些难度,多线程,然后基于安全考虑。
前面说了,消费者要异步消费。而不是我们手动去感知生产者生产东西了,我们去拿来消费。上代码:
public interface EventHandler<T>
{
void onEvent(T event, long sequence) throws Exception;
}
public class StudentEventHandler implements EventHandler<Student> {
@Override
public void onEvent(Student event, long sequence) throws Exception {
System.out.println("我进行异步消费了:"+event.getName());
}
}
新增消费者的处理类,虽然是异步消费,那我们也要告诉异步的线程怎么去消费生产的东西
public interface EventProcessor extends Runnable{
//添加什么东西呢,请稍后
}
public class BatchEventProcessor<T> implements EventProcessor {
/**
* 消费者,消费到哪里的指针
*/
private final Sequence sequence = new Sequence(-1L);
/**
* 存放的环形队列
*/
private Object[] objects;
/**
* 正真处理事件的回调接口。
*/
private final EventHandler<? super T> eventHandler;
public BatchEventProcessor(EventHandler<? super T> eventHandler,Object[] objects) {
this.eventHandler = eventHandler;
this.objects = objects;
}
/**
* 缺少知晓生产者,生产到哪里了
* 这里只拿了条消费者进行消费
*/
@Override
public void run() {
long nextSequence = this.sequence.get() + 1L;
T t = (T)this.objects[(int)nextSequence];
try {
while(true) {
eventHandler.onEvent(t, nextSequence);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这两个类的作用是啥???
刚才说了,我们要异步消费,那就需要有一个异步的线程去调用我们的消费工厂
/**
* @Description:
* 这个类型需要后面大改造的,
* 现在只是粗略的实现
*/
public class Sequence {
private long value;
public Sequence() {
this(-1L);
}
public Sequence(long initialValue) {
value=initialValue;
}
public long get() {
return this.value;
}
public void set(long value) {
this.value=value;
}
}
还需要一个消费的指针,明明就一个字段为什么要包装成类呢,因为只有类才能进行值传递。
然后:我们在再之前的 DisMain进行方法添加
/**
* 消费者
*/
private List<BatchEventProcessor> processorList;
private ExecutorService executors = Executors.newCachedThreadPool();
/**
* 传入消费的工厂
* @param eventHandlers
*/
public final void handleEventsWith(final EventHandler<? super T>... eventHandlers)
{
int i = 0;
for(int eventHandlersLength = eventHandlers.length; i < eventHandlersLength; ++i) {
EventHandler<? super T> eventHandler = eventHandlers[i];
BatchEventProcessor<T> batchEventProcessor = new BatchEventProcessor( eventHandler,this.objects);
if( this.processorList==null){
this.processorList = new ArrayList<>();
}
this.processorList.add(batchEventProcessor);
}
}
public void start() {
for (BatchEventProcessor batchEventProcessor : processorList) {
executors.execute(batchEventProcessor);
}
}
就添加以上代码,把我们的消费工厂传入线程里,一个处理方法就是一个线程,当然,我们还要把环对象传入进去。这样才能知道生产者生产了哪些,然后才能进行消费。这里start方法就是启动相应消费方法的线程。
然后我们写个Main函数:
public class App2
{
public static void main( String[] args )
{
DisMain<Student> disMain = new DisMain(16,new StudentFactory());
StudentEventHandler studentEventHandler =new StudentEventHandler();
disMain.handleEventsWith(studentEventHandler);
disMain.start();
Student stu = new Student();
stu.setId(1);
stu.setName("test");
EventTranslatorOneArg translator = new StudentEventTranslator();
disMain.put(translator,stu);
}
}
细心的铜学,可能发现以上有一个问题
就是 消费线程里,直接拿环里的数据进行消费,但他完全不知道消费者消费到哪里了。就蠢蠢的一直消费。所以这里还缺少一个消费者得知道生产者生产到哪里了。
这里可能有人就想到了,刚刚不是有一个对象Sequence嘛,我只要在DisMain里面维护一个这样对象,生产的时候往里面数字递增,然后初始化消费线程的时候(就是初始化BatchEventProcessor),把这个对象传进去,那每个消费者不是拿到这个对象了嘛。确认这样可行,但这样可有一个缺陷。下一章我先按这个想法实现,然后再告诉各位它的缺陷