Java的ExecutorService的shutdownNow()方法并不能保证一定会结束线程的解决办法
这几天使用ExecutorService的时候遇到了在Task内部进行读取文件操作而导致死循环的问题,当我试图调用shutdownNow()方法的时候,发现并不是像我预想的一样会理解结束线程。我在JDK的API文档中看到了相关解释,Oracle官方的解释是并不保证会结束线程。原文在此:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
我这里引述一下,注意红色部分:
-
shutdownNow
List<Runnable> shutdownNow()
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.This method does not wait for actively executing tasks to terminate. Use
awaitTerminationto do that.There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via
Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.- Returns:
- list of tasks that never commenced execution
- Throws:
SecurityException- if a security manager exists and shutting down this ExecutorService may manipulate threads that the caller is not permitted to modify because it does not holdRuntimePermission("modifyThread"), or the security manager'scheckAccessmethod denies access.
我搜索了之后,发现国外有个老哥实现了一个ExecutorService貌似可以结束线程,但是我没有仔细看,我稍微修改了一下,让它能够在我的项目中跑起来,目前看没有什么问题,
国外老哥的代码在这里:java - How to force terminate all workers in ThreadPoolExecutor immediately - Stack Overflow
我略微修改了一下,代码如下:
package com.xxx.api.utils; import cn.hutool.core.thread.ThreadFactoryBuilder; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class KillableThreadPoolExecutor extends ThreadPoolExecutor { private final Map<Runnable, Thread> executingThreads; public KillableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, String threadNamePrefix) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new LinkedBlockingDeque<Runnable>(), ThreadFactoryBuilder.create().build()); executingThreads = new HashMap<>(maximumPoolSize); } @Override protected synchronized void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); executingThreads.put(r, t); } @Override protected synchronized void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if(executingThreads.containsKey(r)) { executingThreads.remove(r); } } @Override public synchronized List<Runnable> shutdownNow() { List<Runnable> runnables = super.shutdownNow(); for(Thread t : executingThreads.values()) { t.stop(); } return runnables; } }
使用:
KillableThreadPoolExecutor killableThreadPoolExecutor = new KillableThreadPoolExecutor(1, 1, 5, TimeUnit.SECONDS, ""); FutureTask<?> futureTask = new FutureTask(() -> { ResultEntity docTmp = null; //耗时操作可能会死循环,所以放到线程中进行监控 docTmp = new ResultEntity(inPathStream); return docTmp; }); Future<?> submit = killableThreadPoolExecutor.submit(futureTask); try { //System.out.println(DateUtil.now()); //等待20s,否则认为超时,死循环了 Object obj = futureTask.get(20, TimeUnit.SECONDS); // System.out.println(DateUtil.now()); if (null == obj) { //超时 pdfPageCount = 0; } else { doc = (ResultEntity) obj; //页数 pdfPageCount = doc.getPageCount(); } } catch (TimeoutException e) { killableThreadPoolExecutor.shutdownNow(); } catch (Exception e) { killableThreadPoolExecutor.shutdownNow(); } finally { //System.out.println(DateUtil.now()); killableThreadPoolExecutor.shutdownNow(); }
////////////////////////////////
////////Sixi. Let it be.../////
//////////////////////////////
浙公网安备 33010602011771号