EasyAdminThreadPoolExecutor.java 5.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
package com.laker.admin.framework.ext.thread;

import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import net.bull.javamelody.internal.common.LOG;

import java.util.concurrent.*;

/**
 * 自定义扩展线程池用于捕获执行中异常,防止异常被吞
11 12 13
 * <p>
 * 强烈建议使用EasyAdminMDCThreadPoolExecutor
 * </p>
14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * @author laker
 */
@Slf4j
public class EasyAdminThreadPoolExecutor extends ThreadPoolExecutor {
    /**
     * 简易线程池构造器
     *
     * @param poolSize  线程池大小,e.g:60
     * @param queueSize 等待队列,e.g:1000
     * @param prefix    线程名前缀,e.g:MCP-POOL
     */
    public EasyAdminThreadPoolExecutor(int poolSize, int queueSize, String prefix) {
        super(poolSize, poolSize, 60, TimeUnit.SECONDS,
lakernote's avatar
lakernote 已提交
28
                new LinkedBlockingQueue<>(queueSize), ThreadUtil
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
                        .newNamedThreadFactory(prefix + "-", false),
                new EasyAdminRejectPolicy());
        // 非核心线程如果处于闲置状态超过该值,就会被销毁。如果设置allowCoreThreadTimeOut(true),则会也作用于核心线程。
        this.allowCoreThreadTimeOut(true);
    }

    public EasyAdminThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
                                       long keepAliveTime, TimeUnit unit,
                                       BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                threadFactory, new EasyAdminRejectPolicy());
        // 非核心线程如果处于闲置状态超过该值,就会被销毁。如果设置allowCoreThreadTimeOut(true),则会也作用于核心线程。
        this.allowCoreThreadTimeOut(true);
    }


    @Override
    public void execute(Runnable command) {
        super.execute(command);
    }

    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(task);
    }

    @Override
    public Future<?> submit(Callable task) {
        return super.submit(task);
    }

    /**
     * <pre>
     *
     * 这个实现什么也不做,但可以在子类中定制。
     * 注意:为了正确地嵌套多个重写,子类通常应该在该方法结束时调用super.beforeexecute。
     * 在给定线程中执行给定的可运行项之前调用的方法。
     * 此方法由将执行任务r的线程t调用,并可用于重新初始化线程局部变量或执行日志记录。
     *
     *
     * 如果beforeExecute抛出一个RuntimeException,那么任务将不被执行,并且afterExecute也不会被调用
     * 参数 t:t将运行任务r的线程
     * 参数 r:r将要执行的任务
     * </pre>
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        log.debug("beforeExecute-线程:{},任务:{}", t, r);
    }

    /**
     * <pre>
     * XXX 这里虽然有兜底的抓取异常,但是也会导致线程的销毁重建,表现为 线程大小2 A-1,A-2 会一直递增 。。A-100
     * 所以最好还是在 POOL.execute()中加入try catch包裹
     * 这个实现什么也不做,但可以在子类中定制。
     * 注意:为了正确地嵌套多个重写,子类通常应该在这个方法的开头调用super.afterexecute。
     * 在执行给定的可运行文件完成时调用的方法.
     *
     * 无论任务是从run中正常返回,还是抛出一个异常而返回,afterExecute都会被调用
     * 如果任务在完成后带有一个Error,那么就不会调用afterExecute
     *
     * 参数 r 如果是 submit提交的 任务,或者是FutureTask任务,则异常不在参数t中,而是如下方式获取
     * </pre>
     */
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
97 98 99 100 101 102 103 104 105 106 107 108
        if (t == null && r instanceof Future) {
            try {
//                Object result = ((Future<?>) r).get();
                ((Future<?>) r).get();
            } catch (CancellationException ce) {
                t = ce;
            } catch (ExecutionException ee) {
                t = ee.getCause();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt(); // ignore/reset
            }
        }
109
        if (t != null) {
110
            log.error("线程池中的任务执行异常!!!", t);
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
        }
        log.debug("afterExecute-任务:{},异常:{}", r, t);
    }

    /**
     * <pre>
     * exec.shutdown();
     * 当执行器终止时调用的方法。默认实现什么也不做。
     * 注意:为了正确地嵌套多个重写,子类通常应该在这个方法中调用super.terminated。
     * 在线程池完成关闭时调用terminated
     * 也就是在所有任务都已经完成并且所有工作者线程也已经关闭后
     * ,terminated可以用来释放Executor在其生命周期里分配的各种资源,此外还可以执行发送通知、记录日志或者手机finalize统计等操作
     * </pre>
     */
    @Override
    protected void terminated() {
        super.terminated();
        LOG.debug("线程池关闭鸟!!");
    }
}