All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.yuyenews.data.processing.pac.MagicianProducer Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
package com.github.yuyenews.data.processing.pac;


import com.github.yuyenews.data.processing.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 生产者线程
 */
public abstract class MagicianProducer implements Runnable {

    private Logger logger = LoggerFactory.getLogger(MagicianProducer.class);

    /**
     * ID
     */
    private String id;

    /**
     * 它所对应的消费者
     */
    private List consumers;

    /**
     * 他所对应的空闲消费者
     */
    private List freeConsumers;

    /**
     * 是否要停止
     */
    private boolean shutdown;

    /**
     * 是否等所有消费者都空了以后,才进行下一轮
     * 这个配置是跟loop配合使用的,如果loop为fale,那么这个配置将没有意义
     */
    private boolean allFree;

    /**
     * 是否持续生产
     * 如果设置为false,那么producer方法只会执行一次,完成后本线程将直接结束
     * 如果设置为true,那么producer方法会一直循环执行
     */
    private boolean loop;

    public MagicianProducer(){
        this.shutdown = false;
        this.loop = getLoop();
        this.allFree = getAllFree();
        this.id = getId();
        if(StringUtils.isEmpty(this.id)){
            throw new NullPointerException("producer id cannot empty");
        }
    }

    /**
     * 添加消费者
     * @param consumers
     */
    public void addConsumer(List consumers){
        this.consumers = consumers;
        for(MagicianConsumer consumer : this.consumers){
            consumer.initProducerTaskCount(id);
        }
    }

    /**
     * 给消费者投喂任务
     * @param t
     */
    public void publish(Object t){
        if(freeConsumers == null || freeConsumers.size() == 0){
            throw new NullPointerException("");
        }
        for(MagicianConsumer consumer : freeConsumers){
            consumer.addTask(new TaskData(id, t));
        }
    }

    /**
     * 生产数据
     */
    @Override
    public void run(){
        freeConsumers = consumers;

        while (shutdown == false){
            try {
                // 生产数据,并投喂给消费者
                producer();

                // 如果loop设置为false,代表只执行一次,所以直接跳出run方法
                if(loop == false){
                    return;
                }

                // 一轮投喂结束后,检测有没有空闲消费者,如果没有就阻塞在这,直到有空闲消费者出现
                await();
            } catch (Exception e){
                logger.error("DataProducer run error, id:{}", id, e);
            }
        }
    }

    /**
     * 检测有没有空闲消费者,如果没有就阻塞在这,直到有空闲消费者出现
     */
    private void await(){
        while (true) {
            try {
                // 检测有没有空闲消费者
                freeConsumers = new ArrayList<>();
                for (MagicianConsumer consumer : consumers) {
                    if (consumer.isPending(id)) {
                        freeConsumers.add(consumer);
                    } else if (allFree) {
                        // 如果allFree设置为true,那么只要发现了不空闲的消费者就会继续等待
                        // 直到所有消费者都空闲了才进行下一轮
                        freeConsumers = new ArrayList<>();
                        break;
                    }
                }

                // 如果这里能拿到空闲的消费者,就直接进行下一轮
                // 而且生产者发布的数据只会推送到这几个消费者里面
                // 这是为了照顾消费者的消费能力,如果不管不顾随便投喂,会导致队列积压,造成内存溢出
                if (freeConsumers.size() > 0) {
                    break;
                }

                // 没有就阻塞100毫秒,然后再检测一次
                Thread.sleep(100);
                logger.info("DataProducer execProducer awaiting, id:{}......", id);
            } catch (Exception e){
                logger.error("DataProducer execProducer await error, id:{}", id, e);
            }
        }
    }

    /**
     * 停止数据生产
     */
    public void shutDownNow(){
        this.shutdown = true;
    }

    /**
     * 获取ID
     * @return
     */
    public String getId(){
        return this.getClass().getName();
    }

    /**
     * 生产数据
     */
    public abstract void producer();

    /**
     * 是否持续生产
     * 如果设置为false,那么producer方法只会执行一次,完成后本线程将直接结束
     * 如果设置为true,那么producer方法会一直循环执行
     */
    public boolean getLoop(){
        return true;
    }

    /**
     * 是否等所有消费者都空了以后,才进行下一轮
     * 这个配置是跟loop配合使用的,如果loop为fale,那么这个配置将没有意义
     * @return
     */
    public boolean getAllFree(){
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy