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 awaitTermination to 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 hold RuntimePermission("modifyThread"), or the security manager's checkAccess method 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();
            }

 

posted on 2022-11-29 15:07  sixiiweb  阅读(666)  评论(0编辑  收藏  举报

导航