前言:之前说了,先按照上一章结尾所说去实现。消费线程里持有生产者的生产指针。
上代码:
package com.wm;
import com.wm.factory.EventFactory;
import com.wm.factory.EventHandler;
import com.wm.factory.EventTranslatorOneArg;
import com.wm.main.Sequence;
import com.wm.processor.BatchEventProcessor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Date: 2019-09-23 14:59
* @Description:
*/
public class DisMain<T> {
/**
* 存放的环形队列
*/
private Object[] objects;
/**
* 尾部指针
*/
private int tail;
/**
* 头部指针
*/
private int head;
/**
* 环形大小
*/
public int ringBuffSie;
/**
* 生产者的指针
*/
private Sequence producer= new Sequence();
/**
* 消费者
*/
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,producer,ringBuffSie);
if( this.processorList==null){
this.processorList = new ArrayList<>();
}
this.processorList.add(batchEventProcessor);
}
}
public void start() {
for (BatchEventProcessor batchEventProcessor : processorList) {
executors.execute(batchEventProcessor);
}
}
public DisMain(int ringBuffSie, EventFactory eventFactory) {
this.ringBuffSie = ringBuffSie;
objects = new Object[ringBuffSie];
for (int i = 0; i <ringBuffSie ; i++) {
objects[i] =eventFactory.newInstance();
}
}
/**
* 判断环形是否为空
*
* @return
*/
public boolean isEmpty() {
if (tail == head) {
return true;
}
return false;
}
public boolean put(T obj){
if(isFull()){
return false;
}else{
objects[tail%ringBuffSie]=obj;
tail++;
return true;
}
}
public <A> boolean put(EventTranslatorOneArg<T,A> arg,A arg0){
if(isFull()){
return false;
}else{
int position = tail%ringBuffSie;
this.producer.set(tail);
T t = (T)objects[position] ;
arg.translateTo(t,tail,arg0);
tail++;
return true;
}
}
public T get(){
if(isEmpty()){
return null;
}else{
Object obj = objects[head];
head++;
return (T)obj;
}
}
/**
* 判断环形是否填满
*
* @return
*/
public boolean isFull() {
//现在的位置
int nowPro = tail - ringBuffSie;
if ((nowPro + 1) == head) {
return true;
}
return false;
}
/**
* 获取所有未消费的对象列表
*
* @return
*/
public List<T> getObjects() {
List<T> list = new ArrayList<>();
if (isEmpty()) {
//环形为空
return null;
}
//生产跑了多少圈
int proRoundSize = tail % ringBuffSie;
//消费跑了多少圈
int consumerRoundSize = head % ringBuffSie;
// 消费者和生产者跑了同样的圈数
if (proRoundSize == consumerRoundSize) {
for (int i = head + 1; i < tail; i++) {
list.add((T)objects[i]);
}
} else if (proRoundSize > consumerRoundSize) {
for (int i = head + 1; i < consumerRoundSize * ringBuffSie; i++) {
list.add((T)objects[i - consumerRoundSize * ringBuffSie]);
}
int cn = tail - proRoundSize * ringBuffSie;
for (int i = 0; i < cn; i++) {
list.add((T)objects[i]);
}
}
return list;
}
}
看以上代码:新增
- 生产者的指针
- 初始化消费者线程的时候,把指针传进去
- put的时候,把tail赋值到生产者的指针里
public class BatchEventProcessor<T> implements EventProcessor {
/**
* 消费者,消费到哪里的指针
*/
private final Sequence sequence = new Sequence(-1L);
/**
* 生产者的指针
*/
private Sequence producer;
/**
* 存放的环形队列
*/
private Object[] objects;
private int ringBuffSize;
/**
* 正真处理事件的回调接口。
*/
private final EventHandler<? super T> eventHandler;
public BatchEventProcessor(EventHandler<? super T> eventHandler,Object[] objects,Sequence producer,int ringBuffSize) {
this.eventHandler = eventHandler;
this.objects = objects;
this.producer = producer;
this.ringBuffSize = ringBuffSize;
}
@Override
public void run() {
long nextSequence = this.sequence.get() + 1L;
try {
while(true) {
if(producer.get()>sequence.get()){
T t = (T)this.objects[(int)nextSequence%ringBuffSize];
eventHandler.onEvent(t, nextSequence);
sequence.set(nextSequence);
nextSequence++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
看以上代码确实,好像解决了,但问题来了。我知道了生产者的位置,但生产者却不知道消费者的位置,所以万一生产者生产过快,覆盖了消费者怎么办,所以这时候需要一个中间类,这个类来记录消费者的指针和生产者的指针。来避免产生以上的问题。
public static void main( String[] args )
{
DisMain<Student> disMain = new DisMain(16,new StudentFactory());
StudentEventHandler studentEventHandler =new StudentEventHandler();
disMain.handleEventsWith(studentEventHandler);
disMain.start();
EventTranslatorOneArg translator = new StudentEventTranslator();
Student stu = new Student();
for (int i = 0; i <20 ; i++) {
stu.setId(i);
stu.setName("test"+i);
disMain.put(translator,stu);
}
}
可以试着运行下,最多消费到14,之后就不能运行了。因为isFull的原因
上面DisMain 的 isFull 也需要修改,因为我现在消费者的指针不在DisMain里面