多线程处理任务

业务需求是这样:接受大量性能数据,要求多线程处理性能数据,且在任一时刻同种性能数据只能有一条在处理。

这里有5个类:

ProcessScheduler:入口,用于接受性能数据,并将每条性能数据加到队列中处理

ActionExecutor:线程池包装类

ActionQueue:任务队列类,用于保存同种性能任务,保证线程安全及,队列中只有一条任务在一个时刻 处理

ProcessAction:任务类,每条性能任务包装成一个任务,且对数据处理的业务逻辑在此类中

ActionCommand:command类,实现Runnable接口,包装任务类,用于线程池处理

以下代码以最简洁方式呈现

public final class ActionQueue
{
//队列内部实现,其实用queue也行
    private final List<ProcessAction> runQueue = new ArrayList<ProcessAction>();
//锁对象,保证同一时刻只能存或取
    private final Object lockQueue = new Object();
//true代表这个队列中的同种任务有一个在处理当中
    public boolean IS_RUNNING = false;

    public ActionQueue(ProcessAction action)
    {
        addProcessAction(action);
    }
    public void addProcessAction(ProcessAction action)
    {
        synchronized (lockQueue)
        {
            runQueue.add(action);
        }
    }
    //  若这时没有这种任务在处理,则从actionQueue中获得一个可执行action,否则返回null
    public ProcessAction borrowOneCanExecuteAction()
    {
        synchronized (lockQueue)
        {
            if (!IS_RUNNING && runQueue.size()>0)
            {
                ProcessAction action = runQueue.get(0);
                runQueue.remove(0);
                IS_RUNNING = true;
                return action;
            }
            return null;
        }
    }

}
扫描二维码关注公众号,回复: 227022 查看本文章
public final class ProcessAction
{
//任务要处理的数据
    private RawData data;
//同种数据的标识
    private String location;
    public ProcessAction(RawData data)
    {
        this.data = data;
        this.location = data.getLocation();
    }

    public void execute()
    {
        //这里是数据处理的业务逻辑
    }

}
public final class ActionCommand implements Runnable
{
//同种任务所在队列
    private final ActionQueue queue;
//包装的任务
    private final ProcessAction action;
    public ActionCommand(ProcessAction action, ActionQueue queue)
    {
        this.action = action;
        this.queue = queue;
    }
    public void run()
    {
//处理任务内部逻辑,完成后设置队列IS_RUNNING标识为false,接着调用方法处理此任务的下一个同类型任务
        action.execute();
        queue.IS_RUNNING = false;
        ProcessScheduler.instance().exeActionByLocation(action.getLocation());
    }

}
public final class ProcessScheduler
{
//单例
    private static ProcessScheduler inst = new ProcessScheduler();
//线程安全Map,key值是相同任务的标识,value值是存储相同任务的队列
    private final ConcurrentHashMap<String, ActionQueue> actionQueueMap = new ConcurrentHashMap<String, ActionQueue>();
    private final ActionExecutor actionExecutor = new ActionExecutor();
    private boolean bStart = false;
    public static ProcessScheduler instance()
    {
        return inst;
    }
    private ProcessScheduler()
    {
    }
    public void process(List<RawData> datas)
    {
        for (RawData data : datas)
        {
            String location = data.getLocation();
            ProcessAction action = new ProcessAction(data);
            addAction(location, action);
        }
    }

    private void addAction(String location, ProcessAction action)
    {
        if (location == null || action == null)
        {
            return;
        }
        if (!bStart)
        {
            start();
        }
//获取该任务所属队列,将任务加入队列,并处理队列中一条任务
        ActionQueue queueFind = actionQueueMap.putIfAbsent(location,new ActionQueue());
        if(queueFind == null)
        {
            queueFind = actionQueueMap.putIfAbsent(location, new ActionQueue());
        }
        queueFind.addProcessAction(action);
        processQueue(queueFind);
    }

    // 从任务队列仓库中根据location获取队列,并尝试处理队列中一条可处理任务
    public void exeActionByLocation(String location)
    {
        LOGGER.debug("Performs Process ProcessScheduler exeActionBylocation :{}",location);
        ActionQueue queueFind = actionQueueMap.get(location);
        if (queueFind == null)
        {
            return;
        }
        processQueue(queueFind);
    }

    // 尝试从任务队列queue取一条任务 并将其放入线程池处理
    private void processQueue(ActionQueue queue)
    {
        ProcessAction exeAction = queue.borrowOneCanExecuteAction();
        if (exeAction != null)
        {
            actionExecutor.executeAction(exeAction, queue);
        }
    }

   //设置状态bStart为true保证start方法只执行一次 调用actionExecutor的start方法
    private synchronized void start()
    {
        if (bStart)
        {
            return;
        }
        bStart = true;
        this.actionExecutor.start();
    }

}
public final class ActionExecutor
{
    private static final int THREAD_KEEPLIVE_MINUTE = 10;
    private int corePoolSize = 10;
    private int maxCurrentNum = 45;
    private final BlockingQueue<ActionCommand> actionList;
    private ThreadPoolExecutor executor = null;
//这个可以不要,因为只有ProcessScheduler的start方法调用这里的start方法,在外面已经保证只调用一次
    private boolean isStart = false;
//也可以不要,ProcessScheduler保证了只有在线程池start之后,才会往里丢任务
    private final Object lockStart = new Object();
    public ActionExecutor()
    {
        this.actionList = new LinkedBlockingQueue<ActionCommand>();
    }
//处理任务类,将其包装为一个command类,并放入线程池中
    public void executeAction(ProcessAction action, ActionQueue queue)
    {
        ActionCommand command = new ActionCommand(action, queue);
        
        synchronized (lockStart) {
                executor.execute(command);
        }
    }

//实例化线程池对象
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void start()
    {
        synchronized (lockStart) {
            if (isStart) {
                return;
            }
            BlockingQueue blockingQueue = new LinkedBlockingQueue();
            RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy()
            {
                public void rejectedExecution(Runnable r, ThreadPoolExecutor e)
                {
                    ActionExecutor.LOGGER.error("rejected Runnable Execution {}", r);
                }
            };
            this.executor = new ThreadPoolExecutor(corePoolSize, maxCurrentNum,
                    THREAD_KEEPLIVE_MINUTE, TimeUnit.MINUTES,
                    blockingQueue, handler);
            this.executor.setThreadFactory(new SchedulerThreadFactory());

            this.isStart = true;
        }
    }

    // 静态内部类用于包装新建线程,主要功能是设置线程名称、优先级以及将新建线程设为非守护线程
    static class SchedulerThreadFactory implements ThreadFactory
    {
        private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);

        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        public SchedulerThreadFactory()
        {
            this.namePrefix = "PerformanceProcessPool-" + POOL_NUMBER.getAndIncrement() + "-thread-";
        }

        @Override
        public Thread newThread(Runnable r)
        {
            Thread t = new Thread(r, this.namePrefix + this.threadNumber.getAndIncrement());
            if (t.isDaemon()) {
                t.setDaemon(false);
            }
            return t;
        }

    }
}

 这就是对这个业务需求的处理,我已经删减过了

猜你喜欢

转载自xiaoxiaoher.iteye.com/blog/2389953