业务需求是这样:接受大量性能数据,要求多线程处理性能数据,且在任一时刻同种性能数据只能有一条在处理。
这里有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; } } }
这就是对这个业务需求的处理,我已经删减过了