package org.hy.common.thread; import org.hy.common.Date; import org.hy.common.Queue; /** * 任务池。 * * 内含一个相对独立的任务,此任务用于将线程池中空闲的Thread与Task绑定,再执行Task。 * * 任务池采用先进先出原则。 * * @author ZhengWei(HY) * @version V1.0 2012-05-16 * V2.0 2017-02-09 添加:空闲开始时间和扫描任务是否在运行中的状态, * 用其控制扫描任务在长时间空闲时,自动销毁的功能,防止长时间占用资源。 * V3.0 2017-02-21 添加:停止尚未绑定线程开始执行的任务。对于已绑定线程执行的任务不生效。 */ public class TaskPool { private static long $SerialNo = 0; private static TaskPool $TaskPool = new TaskPool(); /** 任务队列 */ private Queue<Task<?>> taskQueue; /** 扫描任务池的任务,即:内含的独立任务 */ private ScanTaskPoolTask scanTaskPoolTask; /** * 单态模式获取唯一的任务池对象实例 * * @return */ public static TaskPool getInstance() { return $TaskPool; } /** * 将任务放入池中 * * @param i_Task */ public synchronized static void putTask(Task<?> i_Task) { if ( i_Task == null ) { return; } i_Task.ready(); // 如果任务池中无排队对象,并且线程池中有空闲线程,则任务不进任务池,而是直接与线程绑定并执行 TaskPool v_TaskPool = getInstance(); if ( v_TaskPool.getQueue().size() == 0 ) { // 以不等待空闲的线程资源的方式 ThreadBase v_ThreadBase = ThreadPool.getThreadInstance(i_Task ,false); if ( v_ThreadBase != null ) { v_ThreadBase.startupAndExecuteTask(); return; } } v_TaskPool.getQueue().put(i_Task); v_TaskPool.startScan(); } /** * 获取队列中的元素。当队列为空时,返回null * * @return */ public synchronized static Task<?> getTask() { Task<?> v_Task = getInstance().getQueue().get(); if ( v_Task != null ) { if ( v_Task.isStop() ) { return getTask(); } } return v_Task; } /** * 获取池中任务数量 * * @return */ public static long size() { return getInstance().getQueue().size(); } /** * 获取曾经进入过队列的任务次数 * * @return */ public static long getPutedCount() { return getInstance().getQueue().getPutedCount(); } /** * 获取曾经出去过队列的任务次数 * * @return */ public static long getOutedCount() { return getInstance().getQueue().getOutedCount(); } private synchronized long GetSerialNo() { return ++$SerialNo; } /** * 私有构造器 */ private TaskPool() { this.taskQueue = new Queue<Task<?>>(); } private Queue<Task<?>> getQueue() { return this.taskQueue; } /** * 启动扫描任务池任务 * * 当空闲超过5分钟后,退出 "永远循环" * * 不用加 synchronized 同步锁,因为调用执行本的方法已经是同步的,并且只有一处调用执行此方法 */ private void startScan() { if ( this.scanTaskPoolTask == null ) { this.scanTaskPoolTask = new ScanTaskPoolTask(); } else { if ( this.scanTaskPoolTask.isScanIsRunning() ) { this.scanTaskPoolTask.refreshWatchInfo(); return; } else { this.scanTaskPoolTask.setScanIsRunning(true); } } // 当线程池中的线程以经不够用时,才会执行本方法,所以要再独立允许一个线程来执行扫描动作。 ThreadBase v_ThreadBase = ThreadPool.getNewThreadInstance(this.scanTaskPoolTask ,10 ,10); v_ThreadBase.startupAndExecuteTask(); } /** * 扫描任务池的任务 * * @author ZhengWei(HY) * @version V1.0 2012-05-16 * V2.0 2017-02-09 添加:空闲开始时间和扫描任务是否在运行中的状态, * 用其控制扫描任务在长时间空闲时,自动销毁的功能,防止长时间占用资源。 */ class ScanTaskPoolTask extends Task<Object> { /** 任务类型常量 */ public final static String $TaskType$ = "ScanTaskPool"; /** 空闲开始时间 */ private long idleBeginTime; /** 扫描任务是否运行中 */ private boolean scanIsRunning; // private StringBuilder buffer; public ScanTaskPoolTask() { super($TaskType$); this.idleBeginTime = Date.getNowTime().getTime(); this.scanIsRunning = true; // this.buffer = new StringBuilder(); } @Override public void execute() { if ( TaskPool.size() >= 1 ) { Task<?> v_Task = TaskPool.getTask(); if ( v_Task != null ) { ThreadBase v_ThreadBase = ThreadPool.getThreadInstance(v_Task ,true); v_ThreadBase.startupAndExecuteTask(); // this.buffer.append(Date.getNowTime().getFullMilli()).append("\t") // .append(v_ThreadBase.getThreadNo()) // .append("\t任务号:").append(v_Task.getTaskNo()).append("\n"); } this.refreshWatchInfo(); idleBeginTime = Date.getNowTime().getTime(); } else { // if ( !Help.isNull(this.buffer.toString()) ) // { // System.out.println(this.buffer.toString()); // this.buffer = new StringBuilder(); // } ThreadPool.sleep(100); // 当空闲超过5分钟后,退出 "永远循环" if ( Date.getNowTime().getTime() - idleBeginTime >= 5 * 60 * 1000 ) { if ( TaskPool.size() <= 0 ) { this.scanIsRunning = false; this.finishTask(); } } } // 永远循环 // this.finishTask(); } /** * 获取:扫描任务是否运行中 */ public boolean isScanIsRunning() { return scanIsRunning; } /** * 设置:扫描任务是否运行中 * * @param scanIsRunning */ public void setScanIsRunning(boolean scanIsRunning) { this.scanIsRunning = scanIsRunning; } @Override public long getSerialNo() { return GetSerialNo(); } @Override public String getTaskDesc() { return "Scan TaskPool waiting task size = " + TaskPool.size(); } } }