开发中遇到这样一个需求。导出excel可能会超时。所以需要做成异步下载。因为下载线程会比较占用cpu资源,可能会有一些慢sql,所以需要控制并发数。
1.建立一个堵塞链表队列,用来存在任务;
2.收到用户请求创建一个下载任务,放在任务队列中。
3.在web.xml中设置一个监听类,启动一个线程定时扫描任务队列,当有任务时执行任务。
4.在执行任务时设置FutureTask超时时间,堵塞当前线程,当前任务一直不结束时,终止任务运行,释放资源。
代码:
<listener> <listener-class>com.taobao.kelude.k3case.listenners.ExportTaskStartupListener</listener-class> </listener>
public class ExportTaskStartupListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { sce.getServletContext().log("定时器销毁"); } @Override public void contextInitialized(ServletContextEvent sce) { sce.getServletContext().log("启动线程池"); sce.getServletContext().log("启动定时器"); sce.getServletContext().log("已经添加任务调度表"); ExportTaskQueueThread exportTaskQueueThread = new ExportTaskQueueThread(); exportTaskQueueThread.start(); } } class ExportTaskQueueThread extends Thread { public void run() { System.out.println("init timer task"); while (true) { // System.out.println("start timer task"); try { if (!ExportTaskPoolManager.queue.isEmpty()) { CallableTask callableTask = ExportTaskPoolManager.queue.take(); FutureTask futureTask = new FutureTask(callableTask); Thread thread = new Thread(futureTask); thread.start(); try { futureTask.get(300, TimeUnit.SECONDS); } catch (TimeoutException e) { System.out.println("export failed for timeout"); futureTask.cancel(true); } } Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } }
public class ExportTaskPoolManager { // public static ExecutorService pool; public static LinkedBlockingQueue<CallableTask> queue = new LinkedBlockingQueue<CallableTask>(); }
public class ExportCaseTask extends CallableTask { private Logger logger = LoggerFactory.getLogger("ExportCaseTask"); private List<Integer> priority; private Integer userId; private Boolean needFormat; private Integer[] suiteIds; private List<Integer> caseIds; private List<Integer> spaceIds; private String name; private String type; public ExportCaseTask(Integer[] suiteIds, List<Integer> caseIds, List<Integer> spaceIds, String name, List<Integer> priority, String type,boolean needFormat, Integer userId) { this.needFormat = needFormat; this.priority = priority; this.userId = userId; this.suiteIds = suiteIds; this.caseIds = caseIds; this.spaceIds = spaceIds; this.name = name; this.type = type; } private TestCaseService testCaseService = (TestCaseService) SpringContextUtils.getBean("testCaseService"); public Object call() throws Exception { try { testCaseService.generateASync(suiteIds, caseIds, spaceIds, name, priority, type, needFormat, userId); logger.info("generateASync ok"); } catch (Exception e) { e.printStackTrace(); } finally { } return 1; } }