All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.shepherdviolet.glacimon.java.concurrent.ThreadPoolExecutorUtils Maven / Gradle / Ivy

/*
 * Copyright (C) 2022-2022 S.Violet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Project GitHub: https://github.com/shepherdviolet/glacimon
 * Email: [email protected]
 */

package com.github.shepherdviolet.glacimon.java.concurrent;

import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.*;

/**
 * 

ThreadPoolExecutor线程池工具

* *

* 1.特别注意!!! 核心线程会一直存在, 执行任务或挂起等待, 直到线程池shutdown. 即使线程池无人持有(引用), GC也不会销毁parking的线程. * 非核心线程在任务完成且闲置超过指定时间(keepAliveTime)后结束. 用户线程(默认, 非Daemon线程)会阻止JVM正常停止(kill, 非kill -9), * 直到所有的用户线程结束.
* --1.1.如果线程池需要/可能反复创建, 且核心线程数大于0 (或非核心线程保活时间很长), 必须在合适的时候调用shutdown/shutdownNow方法关闭 * 线程池, 否则核心线程会一直存在.
* --1.2.如果线程池不会反复创建, 但核心线程数大于0的 (或非核心线程保活时间很长), 可以选择设置为Daemon线程, 或者在合适的时候调用 * shutdown/shutdownNow方法, 否则会影响JVM正常停止.
* 2.线程数达到corePoolSize之前, 每次执行(execute)都会创建一个新的核心线程.
* 3.当线程数达到corePoolSize之后, 会将任务(Runnable)加入工作队列(workQueue).
* --3.1.如果此时线程数为0, 则会创建一个非核心线程(仅此一个).
* --3.2.如果任务入队成功, 存活的线程会从队列中获取任务执行.
* --3.3.如果任务入队失败(BlockingQueue.offer(E e)返回false), 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* 4.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --4.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --4.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
* 5.使用SynchronousQueue工作队列时, 并发任务会直接增加线程(包括核心线程和非核心线程).
* --5.1.当并发量超过maximumPoolSize时, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般maximumPoolSize >= corePoolSize.
*

* * @author shepherdviolet */ public class ThreadPoolExecutorUtils { private static final Set POOL = Collections.newSetFromMap(new WeakHashMap()); /** *

会超时的单线程池, 核心线程数0, 最大线程数1, 队列长度Integer.MAX_VALUE

* *

* 如果线程池需要/可能反复创建, 且keepAliveSeconds较大, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会存在很久.
* 如果线程池不会反复创建, 但keepAliveSeconds较大, 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数为0, 所以如果keepAliveSeconds较小的话, 不管它也没事. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
*

* * @param keepAliveSeconds 线程保活时间(秒) * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) */ public static ThreadPoolExecutor createSingle(long keepAliveSeconds, String threadNameFormat){ return create( 0, 1, keepAliveSeconds, threadNameFormat, new LinkedBlockingQueue(), new ThreadPoolExecutor.AbortPolicy(), null); } /** *

会超时的单线程池, 核心线程数0, 最大线程数1, 队列长度Integer.MAX_VALUE

* *

* 如果线程池需要/可能反复创建, 且keepAliveSeconds较大, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会存在很久.
* 如果线程池不会反复创建, 但keepAliveSeconds较大, 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数为0, 所以如果keepAliveSeconds较小的话, 不管它也没事. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
*

* * @param keepAliveSeconds 线程保活时间(秒) * @param threadFactory 线程工厂 (可以设置线程名称, 是否daemon等) */ public static ThreadPoolExecutor createSingle(long keepAliveSeconds, ThreadFactory threadFactory){ return create( 0, 1, keepAliveSeconds, threadFactory, new LinkedBlockingQueue(), new ThreadPoolExecutor.AbortPolicy(), null); } /** *

[特殊用途]惰性单线程池, 核心线程数0, 最大线程数1, 队列长度1, 策略DiscardPolicy

* *

* 如果线程池需要/可能反复创建, 且keepAliveSeconds较大, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会存在很久.
* 如果线程池不会反复创建, 但keepAliveSeconds较大, 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数为0, 所以如果keepAliveSeconds较小的话, 不管它也没事. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 警告: 请明确用途后再使用!!!
* WARNING: This ThreadPool should be used with caution!!!
*

* *

特性:

* *

* 1.单线程, 同时只能执行一个任务, 线程有存活期限.
* 2.队列长度1, 同时执行(execute)多个任务时, 至多执行2个, 多余的任务会被抛弃(且不会抛出异常).
* 3.能保证在最后一次执行(execute)之后, 有一次完整的任务处理(Runnable.run()).
* 4.用于实现调度/清扫. 例如: 实现一个调度任务, 从某个队列中, 循环获取元素进行处理的功能. 在每次元素入队列时, 使用本线程池 * 执行调度任务, 任务中循环处理队列中的元素直到队列为空. 因为是单线程池, 所以处理逻辑不会被同时重复执行; 因为长度为1的等待 * 队列, 能保证队列中的元素都被及时处理(每次execute之后必然会有一次完整的处理流程); 因为核心线程数0, 闲时能释放线程, 比无限 * 循环的实现方式占资源少, 比定时执行的实现方式实时性高.
*

* *

笔记:

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
*

* *

如果忽略掉本工具类提供的新特性, 可以简化为:

*
     *          // 这么写就没有本工具类提供的新特性了: 自定义线程名, 执行前后监听, 统一管理和销毁...
     *          new ThreadPoolExecutor(0, 1, 60L,
     *                     TimeUnit.SECONDS,
     *                     new LinkedBlockingQueue(1),
     *                     Executors.defaultThreadFactory(),
     *                     new ThreadPoolExecutor.DiscardPolicy());
     * 
* * @param keepAliveSeconds 线程保活时间(秒) * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) */ public static ThreadPoolExecutor createLazy(long keepAliveSeconds, String threadNameFormat){ return create( 0, 1, keepAliveSeconds, threadNameFormat, new LinkedBlockingQueue(1), new ThreadPoolExecutor.DiscardPolicy(), null); } /** *

[特殊用途]惰性单线程池, 核心线程数0, 最大线程数1, 队列长度1, 策略DiscardPolicy

* *

* 如果线程池需要/可能反复创建, 且keepAliveSeconds较大, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会存在很久.
* 如果线程池不会反复创建, 但keepAliveSeconds较大, 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数为0, 所以如果keepAliveSeconds较小的话, 不管它也没事. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 警告: 请明确用途后再使用!!!
* WARNING: This ThreadPool should be used with caution!!!
*

* *

特性:

* *

* 1.单线程, 同时只能执行一个任务, 线程有存活期限.
* 2.队列长度1, 同时执行(execute)多个任务时, 至多执行2个, 多余的任务会被抛弃(且不会抛出异常).
* 3.能保证在最后一次执行(execute)之后, 有一次完整的任务处理(Runnable.run()).
* 4.用于实现调度/清扫. 例如: 实现一个调度任务, 从某个队列中, 循环获取元素进行处理的功能. 在每次元素入队列时, 使用本线程池 * 执行调度任务, 任务中循环处理队列中的元素直到队列为空. 因为是单线程池, 所以处理逻辑不会被同时重复执行; 因为长度为1的等待 * 队列, 能保证队列中的元素都被及时处理(每次execute之后必然会有一次完整的处理流程); 因为核心线程数0, 闲时能释放线程, 比无限 * 循环的实现方式占资源少, 比定时执行的实现方式实时性高.
*

* *

笔记:

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
*

* *

如果忽略掉本工具类提供的新特性, 可以简化为:

*
     *          // 这么写就没有本工具类提供的新特性了: 自定义线程名, 执行前后监听, 统一管理和销毁...
     *          new ThreadPoolExecutor(0, 1, 60L,
     *                     TimeUnit.SECONDS,
     *                     new LinkedBlockingQueue(1),
     *                     Executors.defaultThreadFactory(),
     *                     new ThreadPoolExecutor.DiscardPolicy());
     * 
* * @param keepAliveSeconds 线程保活时间(秒) * @param threadFactory 线程工厂 (可以设置线程名称, 是否daemon等) */ public static ThreadPoolExecutor createLazy(long keepAliveSeconds, ThreadFactory threadFactory){ return create( 0, 1, keepAliveSeconds, threadFactory, new LinkedBlockingQueue(1), new ThreadPoolExecutor.DiscardPolicy(), null); } /** *

固定线程数的线程池, 核心线程数poolSize, 最大线程数poolSize, 队列长度Integer.MAX_VALUE

* *

* !!!!!!注意!!!!!!
* 如果线程池需要/可能反复创建, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 也可以选择设置为Daemon线程(shutdown更好), 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数一定大于0, 所以至少要采取一种措施. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
*

* * @param poolSize 线程数 * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) */ public static ThreadPoolExecutor createFixed(int poolSize, String threadNameFormat){ return create( poolSize, poolSize, 0L, threadNameFormat, new LinkedBlockingQueue(), new ThreadPoolExecutor.AbortPolicy(), null); } /** *

固定线程数的线程池, 核心线程数poolSize, 最大线程数poolSize, 队列长度Integer.MAX_VALUE

* *

* !!!!!!注意!!!!!!
* 如果线程池需要/可能反复创建, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 也可以选择设置为Daemon线程(shutdown更好), 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数一定大于0, 所以至少要采取一种措施. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
*

* * @param poolSize 线程数 * @param threadFactory 线程工厂 (可以设置线程名称, 是否daemon等) */ public static ThreadPoolExecutor createFixed(int poolSize, ThreadFactory threadFactory){ return create( poolSize, poolSize, 0L, threadFactory, new LinkedBlockingQueue(), new ThreadPoolExecutor.AbortPolicy(), null); } /** *

动态线程数的线程池, 核心线程数corePoolSize, 最大线程数maximumPoolSize, 队列长度0

* *

* !!注意!! * 如果线程池需要/可能反复创建, 且corePoolSize大于0 (或keepAliveSeconds较大), 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 但corePoolSize大于0 (或keepAliveSeconds较大), 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
*

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 6.使用SynchronousQueue工作队列时, 并发任务会直接增加线程(包括核心线程和非核心线程).
* --6.1.当并发量超过maximumPoolSize时, 拒绝任务并由RejectedExecutionHandler处理.
* --6.2.因此, 一般maximumPoolSize >= corePoolSize.
*

* * @param corePoolSize 核心线程数 * @param maximumPoolSize 最大线程数 * @param keepAliveSeconds 线程保活时间(秒) * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) */ public static ThreadPoolExecutor createCached(int corePoolSize, int maximumPoolSize, long keepAliveSeconds, String threadNameFormat){ return create( corePoolSize, maximumPoolSize, keepAliveSeconds, threadNameFormat, new SynchronousQueue(), new ThreadPoolExecutor.AbortPolicy(), null); } /** *

动态线程数的线程池, 核心线程数corePoolSize, 最大线程数maximumPoolSize, 队列长度0

* *

* !!注意!! * 如果线程池需要/可能反复创建, 且corePoolSize大于0 (或keepAliveSeconds较大), 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 但corePoolSize大于0 (或keepAliveSeconds较大), 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
*

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 6.使用SynchronousQueue工作队列时, 并发任务会直接增加线程(包括核心线程和非核心线程).
* --6.1.当并发量超过maximumPoolSize时, 拒绝任务并由RejectedExecutionHandler处理.
* --6.2.因此, 一般maximumPoolSize >= corePoolSize.
*

* * @param corePoolSize 核心线程数 * @param maximumPoolSize 最大线程数 * @param keepAliveSeconds 线程保活时间(秒) * @param threadFactory 线程工厂 (可以设置线程名称, 是否daemon等) */ public static ThreadPoolExecutor createCached(int corePoolSize, int maximumPoolSize, long keepAliveSeconds, ThreadFactory threadFactory){ return create( corePoolSize, maximumPoolSize, keepAliveSeconds, threadFactory, new SynchronousQueue(), new ThreadPoolExecutor.AbortPolicy(), null); } /** *

创建线程池

* *

* !!注意!! * 如果线程池需要/可能反复创建, 且corePoolSize大于0 (或keepAliveSeconds较大), 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 但corePoolSize大于0 (或keepAliveSeconds较大), 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
*

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
* 6.使用SynchronousQueue工作队列时, 并发任务会直接增加线程(包括核心线程和非核心线程).
* --6.1.当并发量超过maximumPoolSize时, 拒绝任务并由RejectedExecutionHandler处理.
* --6.2.因此, 一般maximumPoolSize >= corePoolSize.
*

* * @param corePoolSize 核心线程数 * @param maximumPoolSize 最大线程数 * @param keepAliveSeconds 线程保活时间(秒) * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) * @param workQueue 工作队列 * @param rejectHandler nullable, 拒绝处理器, 默认: new ThreadPoolExecutor.AbortPolicy() * @param executeListener nullable, 监听执行前执行后的事件 */ public static ThreadPoolExecutor create(int corePoolSize, int maximumPoolSize, long keepAliveSeconds, String threadNameFormat, BlockingQueue workQueue, RejectedExecutionHandler rejectHandler, final ExecuteListener executeListener){ return create( corePoolSize, maximumPoolSize, keepAliveSeconds, new GuavaThreadFactoryBuilder().setNameFormat(threadNameFormat).build(), workQueue, rejectHandler, executeListener ); } /** *

创建线程池

* *

* !!注意!! * 如果线程池需要/可能反复创建, 且corePoolSize大于0 (或keepAliveSeconds较大), 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 但corePoolSize大于0 (或keepAliveSeconds较大), 可以选择设置为Daemon线程, 或者在合适的时候调用shutdown/shutdownNow方法, 否则会影响JVM正常停止.
*

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 5.使用LinkedBlockingQueue工作队列时, 在填满核心线程后, 后续任务会加入队列, 队列满之前都不会尝试增加非核心线程.
* --5.1.如果队列满了, 会尝试增加非核心线程. 如果增加失败, 拒绝任务并由RejectedExecutionHandler处理.
* --5.2.因此, 一般corePoolSize == maximumPoolSize, 或者corePoolSize = 0 maximumPoolSize = 1(会超时的单线程池).
* 6.使用SynchronousQueue工作队列时, 并发任务会直接增加线程(包括核心线程和非核心线程).
* --6.1.当并发量超过maximumPoolSize时, 拒绝任务并由RejectedExecutionHandler处理.
* --6.2.因此, 一般maximumPoolSize >= corePoolSize.
*

* * @param corePoolSize 核心线程数 * @param maximumPoolSize 最大线程数 * @param keepAliveSeconds 线程保活时间(秒) * @param threadFactory 线程工厂 * @param workQueue 工作队列 * @param rejectHandler nullable, 拒绝处理器, 默认: new ThreadPoolExecutor.AbortPolicy() * @param executeListener nullable, 监听执行前执行后的事件 */ public static ThreadPoolExecutor create(int corePoolSize, int maximumPoolSize, long keepAliveSeconds, ThreadFactory threadFactory, BlockingQueue workQueue, RejectedExecutionHandler rejectHandler, final ExecuteListener executeListener){ EnhancedThreadPoolExecutor executorService = new EnhancedThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveSeconds, TimeUnit.SECONDS, workQueue, threadFactory, new RejectedExecutionHandlerWrapper(rejectHandler != null ? rejectHandler : new ThreadPoolExecutor.AbortPolicy()), executeListener); synchronized (POOL) { POOL.add(executorService); } return executorService; } /** *

创建定时线程池

* *

* !!!!!!注意!!!!!!
* 如果线程池需要/可能反复创建, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 也可以选择设置为Daemon线程(shutdown更好), 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数一定大于0, 所以至少要采取一种措施. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 1.定时线程池能够延迟/循环执行任务 *

* * @param corePoolSize 核心线程数, >= 1 * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) */ public static ScheduledThreadPoolExecutor createScheduled(int corePoolSize, String threadNameFormat){ return createScheduled(corePoolSize, threadNameFormat, null, null); } /** *

创建定时线程池

* *

* !!!!!!注意!!!!!!
* 如果线程池需要/可能反复创建, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 也可以选择设置为Daemon线程(shutdown更好), 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数一定大于0, 所以至少要采取一种措施. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 1.定时线程池能够延迟/循环执行任务 *

* * @param corePoolSize 核心线程数, >= 1 * @param threadFactory 线程工厂 (可以设置线程名称, 是否daemon等) */ public static ScheduledThreadPoolExecutor createScheduled(int corePoolSize, ThreadFactory threadFactory){ return createScheduled(corePoolSize, threadFactory, null, null); } /** *

创建定时线程池

* *

* !!!!!!注意!!!!!!
* 如果线程池需要/可能反复创建, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 也可以选择设置为Daemon线程(shutdown更好), 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数一定大于0, 所以至少要采取一种措施. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 1.定时线程池能够延迟/循环执行任务 *

* * @param corePoolSize 核心线程数, >= 1 * @param threadNameFormat 线程名称格式(rpc-pool-%s 或者 rpc-pool-%d) * @param rejectHandler nullable, 拒绝处理器, 默认: new ThreadPoolExecutor.AbortPolicy() * @param executeListener nullable, 监听执行前执行后的事件 */ public static ScheduledThreadPoolExecutor createScheduled(int corePoolSize, String threadNameFormat, RejectedExecutionHandler rejectHandler, final ExecuteListener executeListener){ return createScheduled( corePoolSize, new GuavaThreadFactoryBuilder().setNameFormat(threadNameFormat).build(), rejectHandler, executeListener); } /** *

创建定时线程池

* *

* !!!!!!注意!!!!!!
* 如果线程池需要/可能反复创建, 必须在合适的时候调用shutdown/shutdownNow方法关闭线程池, 否则废弃线程池中的线程会一直存在.
* 如果线程池不会反复创建, 也可以选择设置为Daemon线程(shutdown更好), 否则会影响JVM正常停止.
* 因为这个线程池的核心线程数一定大于0, 所以至少要采取一种措施. *

* *

通过ThreadFactory设置守护线程示例: new GuavaThreadFactoryBuilder().setNameFormat("name-%s").setDaemon(true).build()

* *

* 1.定时线程池能够延迟/循环执行任务 *

* * @param corePoolSize 核心线程数, >= 1 * @param threadFactory 线程工厂 * @param rejectHandler nullable, 拒绝处理器, 默认: new ThreadPoolExecutor.AbortPolicy() * @param executeListener nullable, 监听执行前执行后的事件 */ public static ScheduledThreadPoolExecutor createScheduled(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectHandler, final ExecuteListener executeListener){ //JDK8的BUG, corePoolSize=0时会吃CPU(无限循环) //https://bugs.openjdk.java.net/browse/JDK-8129861 if (corePoolSize < 1) { throw new IllegalArgumentException("corePoolSize must >= 1 for ScheduledExecutorService, otherwise it will result in high CPU usage."); } EnhancedScheduledThreadPoolExecutor executorService = new EnhancedScheduledThreadPoolExecutor( corePoolSize, threadFactory, new RejectedExecutionHandlerWrapper(rejectHandler != null ? rejectHandler : new ThreadPoolExecutor.AbortPolicy()), executeListener); synchronized (POOL) { POOL.add(executorService); } return executorService; } /** * 将所有通过此工具创建的ExecutorService停止(shutdownNow, 实际上是向线程发送interrupt信号, * 并不是直接杀死线程). * 谨慎使用此方法, 调用后之前所有创建的ExecutorService都将无法使用, 通常在停止服务时调用. * 另外, 此方法停止的线程池, RejectedExecutionHandler的异常也会被拦截, 不会抛出. */ public static void shutdownNowAll(){ synchronized (POOL) { for (EnhancedExecutor executorService : POOL) { if (executorService != null) { try { executorService.enhancedShutdownNow(); } catch (Throwable ignore){ } } } } } private interface EnhancedExecutor { void enhancedShutdownNow(); } /** * ThreadPoolExecutor加强 */ private static class EnhancedThreadPoolExecutor extends ThreadPoolExecutor implements EnhancedExecutor { private final ExecuteListener executeListener; private final RejectedExecutionHandlerWrapper rejectedExecutionHandlerWrapper; private EnhancedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandlerWrapper handler, ExecuteListener executeListener) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); this.executeListener = executeListener; this.rejectedExecutionHandlerWrapper = handler; } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); if (executeListener != null) { executeListener.beforeExecute(t, r); } } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (executeListener != null) { executeListener.afterExecute(r, t); } } /** * shutdownNow的同时, 屏蔽RejectedExecutionHandler的异常, 忽略异常 */ @Override public void enhancedShutdownNow() { try { rejectedExecutionHandlerWrapper.shutdown(); super.shutdownNow(); } catch (Throwable ignore){ } } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { return super.equals(obj); } } /** * ScheduledThreadPoolExecutor加强 */ private static class EnhancedScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor implements EnhancedExecutor { private final ExecuteListener executeListener; private final RejectedExecutionHandlerWrapper rejectedExecutionHandlerWrapper; private EnhancedScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandlerWrapper handler, ExecuteListener executeListener) { super(corePoolSize, threadFactory, handler); this.executeListener = executeListener; this.rejectedExecutionHandlerWrapper = handler; } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); if (executeListener != null) { executeListener.beforeExecute(t, r); } } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (executeListener != null) { executeListener.afterExecute(r, t); } } /** * shutdownNow的同时, 屏蔽RejectedExecutionHandler的异常, 忽略异常 */ @Override public void enhancedShutdownNow() { try { rejectedExecutionHandlerWrapper.shutdown(); super.shutdownNow(); } catch (Throwable ignore){ } } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { return super.equals(obj); } } /** * RejectedExecutionHandler包装类 */ private static class RejectedExecutionHandlerWrapper implements RejectedExecutionHandler{ private RejectedExecutionHandler provider; private volatile boolean isShutdown = false; private RejectedExecutionHandlerWrapper(RejectedExecutionHandler provider) { this.provider = provider; } @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { /* 如果shutdown状态, 则不抛出异常 */ try { provider.rejectedExecution(r, executor); } catch (Throwable t) { if (isShutdown){ return; } throw t; } } private void shutdown(){ isShutdown = true; } } public interface ExecuteListener { /** * 在Runnable执行前调用 * @param t 线程 * @param r runnable */ void beforeExecute(Thread t, Runnable r); /** * 在Runnable执行后调用 * @param r runnable * @param t 线程 */ void afterExecute(Runnable r, Throwable t); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy