ThreadPoolExecutor学习(一)

线程池参数

1. corePoolSize - 常驻核心线程数,即使空闲时仍保留在池中的线程数,除非设置allowCoreThreadTimeOut为true
2. maximumPoolSize - 池中允许的最大线程数。必须大于或等于1,如果等于corePoolSize那就是固定大小线程池。队列缓存达到上限后,如果还有新任务需要处理,线程池就会创建新的线程。
3. keepAliveTime -表示线程池中线程的空闲时间,当空闲时间达到这个值,线程会被销毁,知道只剩下corePoolSize个线程为止,避免浪费内存和句柄资源
4. unit - keepAliveTime-参数的时间单位
5. workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存 execute 方法提交的 Runnable任务。当请求线程数大于核心线程数时,线程进入 BlockingQueue 阻塞队列。建议使用有界队列,可以增加系统的稳定性和预警能力
6. threadFactory - 用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,可实现ThreadFactory 接口,自定义线程工厂
7. handler - 饱和策略,执行被阻止时使用的处理程序,因为达到线程限制和队列容量,也是一种简单的限流保护
AbortPolicy:直接丢弃并抛出异常(默认情况)
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
DiscardPolicy:不处理,丢弃掉
自定义策略需实现RejectedExecutionHandler接口 :友好的拒绝策略有三种:保存到数据库进行削峰填谷,在空闲时再提取出来执行;转向某个提示页面;打印日志

线程预热
通过调用线程池中prestartAllCoreThreads()和prestartCoreThread()进行核心线程的创建,prestartAllCoreThreads()会创建所有核心线程数,prestartCoreThread()只会创建一个

作用

  1. 降低资源消耗
  2. 提高响应速度
  3. 提高线程的可管理性

线程池简单demo

优雅关闭线程池方法:
利用JVM钩子函数,在虚拟机关闭时调用相关方法即”优雅关闭线程池”。
先通过shutdown等待线程池自身结束,然后等待一段时间,如果没有成功,再调用shutdownNow将等待I/O的任务中断并退出。
shutdown():关闭线程池,将线程池的状态设置为SHUTWDOWN状态,根据拒绝策略拒绝后续提交的任务,继续执行正在的执行的线程以及阻塞队列中的线程,直到所有线程执行完毕
shutdownNow():关闭线程池,将线程池的状态设置为STOP,根据拒绝策略拒绝后续提交的任务,会给所有线程池中的线程发送 interrupt 中断信号,尝试中断这些任务的执行,然后会将任务队列中正在等待的所有任务转移到一个 List 中并返回,我们可以根据返回的任务 List 来进行一些补救的操作,例如记录在案并在后期重试
一般不建议直接使用shutdownNow(),可能会导致正在执行的任务出错

public class ThreadPoolUtils {

    /**
     * 使用volatile关键字保其可见性
     */
    private static volatile ThreadPoolExecutor threadPool = null;

    /** 线程本地变量,用于记录线程异步任务的开始执行时间*/
    private static final ThreadLocal<Long> START_TIME = new ThreadLocal<>();

    /**
     * 无返回值直接执行
     *
     * @param runnable
     */
    public static void execute(Runnable runnable,int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
        getThreadPool().execute(runnable);
    }

    /**
     * 返回值直接执行
     *
     * @param callable
     */
    public static <T> Future<T> submit(Callable<T> callable) {
        return getThreadPool().submit(callable);
    }

    private static ThreadPoolExecutor getThreadPool() {
        if (threadPool == null) {
            synchronized (ThreadPoolUtils.class) {
                // 二次检查
                if (threadPool == null) {
                    // 创建实例之前可能会有一些准备性的耗时工作
                    sleepSecond(300L);
                    // 获取处理器数量
                    int cpuNum = Runtime.getRuntime().availableProcessors();
                    // 根据cpu数量,计算出合理的线程并发数
                    int threadNum = cpuNum * 2 + 1;
                    threadPool = new ThreadPoolExecutor(
                            // 核心线程数
                            threadNum - 1,
                            // 最大线程数
                            threadNum,
                            // 闲置线程存活时间
                            Integer.MAX_VALUE,
                            // 时间单位
                            TimeUnit.MILLISECONDS,
                            // 线程队列
                            new LinkedBlockingDeque<Runnable>(Integer.MAX_VALUE),
                            // 线程工厂
                            Executors.defaultThreadFactory(),
                            // 队列已满,而且当前线程数已经超过最大线程数时的异常处理策略
                            new ThreadPoolExecutor.AbortPolicy() {
                                @Override
                                public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                                    super.rejectedExecution(r, e);
                                }
                            }
                    ){
                        //继承:调度器终止钩子
                        @Override
                        protected void terminated()
                        {
                            System.out.println(("调度器已经终止!"));
                        }
                        //继承:执行前钩子
                        @Override
                        protected void beforeExecute(Thread t, Runnable target)
                        {
                            System.out.println((target + "前钩被执行"));
                            //记录开始执行时间
                            START_TIME.set(System.currentTimeMillis());
                            super.beforeExecute(t, target);
                        }

                        //继承:执行后钩子
                        @Override
                        protected void afterExecute(Runnable target, Throwable t)
                        {
                            super.afterExecute(target, t);
                            //计算执行时长
                            long time = (System.currentTimeMillis() - START_TIME.get()) ;
                            System.out.println((target + " 后钩被执行, 任务执行时长(ms):" + time));
                            //清空本地变量
                            START_TIME.remove();
                        }

                    };


                }
            }

        }

        return threadPool;
    }

    public static void shutdownThreadPoolGracefully(ExecutorService threadPool) {
        // 若已经关闭则返回
        if (threadPool == null || threadPool.isTerminated()) {
            return;
        }
        try {
            threadPool.shutdown();   //拒绝接受新任务
        } catch (SecurityException | NullPointerException e) {
            return;
        }
        try {
            // 等待60秒,等待线程池中的任务完成执行
            if (!threadPool.awaitTermination(60L, TimeUnit.SECONDS)) {
                // 调用 shutdownNow() 方法取消正在执行的任务
                threadPool.shutdownNow();
                // 再次等待60秒,如果还未结束,可以再次尝试,或者直接放弃
                if (!threadPool.awaitTermination(60L, TimeUnit.SECONDS)) {
                    System.err.println("线程池任务未正常执行结束");
                }
            }
        } catch (InterruptedException ie) {
            // 捕获异常,重新调用 shutdownNow()方法
            threadPool.shutdownNow();

        }
        // 仍然没有关闭,循环关闭1000次,每次等待10毫秒
        if (!threadPool.isTerminated()) {
            try {
                for (int i = 0; i < 1000; i++) {
                    if (threadPool.awaitTermination(10, TimeUnit.MILLISECONDS)) {
                        break;
                    }
                    threadPool.shutdownNow();
                }
            } catch (Throwable e) {
                System.err.println(e.getMessage());

            }
        }
    }


    private void SeqOrScheduledTargetThreadPoolLazyHolder(ExecutorService threadPool) {
            //注册JVM关闭时的钩子函数
            Runtime.getRuntime().addShutdownHook(
                    new ShutdownHookThread((InternalLogger) log,
                            (Callable<Void>) () -> {
                                //优雅地关闭线程池
                                shutdownThreadPoolGracefully(threadPool);
                                return null;
                            }));
    }

    public static final void sleepSecond(long seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            log.warn(e.toString());
        }
    }
}

下面参考Rocketmq中代码

public class ShutdownHookThread extends Thread {
    private volatile boolean hasShutdown = false;
    private AtomicInteger shutdownTimes = new AtomicInteger(0);
    private final InternalLogger log;
    private final Callable callback;

    /**
     * Create the standard hook thread, with a call back, by using {@link Callable} interface.
     *
     * @param log The log instance is used in hook thread.
     * @param callback The call back function.
     */
    public ShutdownHookThread(InternalLogger log, Callable callback) {
        super("ShutdownHook");
        this.log = log;
        this.callback = callback;
    }

    /**
     * Thread run method.
     * Invoke when the jvm shutdown.
     * 1. count the invocation times.
     * 2. execute the {@link ShutdownHookThread#callback}, and time it.
     */
    @Override
    public void run() {
        synchronized (this) {
            log.info("shutdown hook was invoked, " + this.shutdownTimes.incrementAndGet() + " times.");
            if (!this.hasShutdown) {
                this.hasShutdown = true;
                long beginTime = System.currentTimeMillis();
                try {
                    this.callback.call();
                } catch (Exception e) {
                    log.error("shutdown hook callback invoked failure.", e);
                }
                long consumingTimeTotal = System.currentTimeMillis() - beginTime;
                log.info("shutdown hook done, consuming time total(ms): " + consumingTimeTotal);
            }
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值