- 自定义线程池创建API
线程池创建通过JUC的接口 Executor 实现, 平时我们使用其实现类 ThreadPoolExecutor 实现自定义线程池。
常用构造函数:public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
- 参数详解
corePoolSize:核心线程数。
maximumPoolSize:最大线程数
keepAliveTime:空闲最大存活时间
unit:存活时间单位
workQueue:任务缓存队列
threadFactory:线程工厂类
handler:拒绝策略
线程池创建线程的规则:默认情况下,线程池创建时启动的线程为0,当任务执行时创建线程来执行任务,并发任务时,首先创建的线程数为设置的corePoolSize ,多余的任务存到 workQueue 队列中,如果队列满了之后,且设置的 maximumPoolSize 大于 corePoolSize ,则会创建新的线程执行任务,对于大于 corePoolSize 数量的线程,再空闲 keepAliveTime 时间后会销毁线程。如果创建的线程达到 maximumPoolSize 还有并发任务等待,则会执行 设置的拒绝策略。
这里有个点需要注意:只有队列满了之后才会创建新的线程数量至maximumPoolSize ,和执行拒绝策略,所以如果队列的大小必须是有界队列,这也是不使用 Executors 默认五种api创建线程池的原因。 - 自定义线程池创建demo
这里设置的核心线程池10,最大线程池16,空闲线程时间10分钟,队列大小为400,默认工厂,抛出异常策略创建。private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,16,10, TimeUnit.MINUTES, new ArrayBlockingQueue<>(400), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
- 队列选择
- 线程工厂类
线程工厂类顾名思义指定线程创建过程,默认的线程创建源码为:static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }
主要是实现 ThreadFactory 实现 newThread 来指定创建线程的过程 ,从源码中我们可以看出,指定线程为用户线程(非守护线程),设置优先级为默认优先级。 使用 Thread的构造函数创建Thread对象。Thread的构造函数这里不展开介绍
我们也可以自定义一个线程工厂类,例:
public class NameThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); return thread; } }
这里使用最简单方式演示,当然我们也可以使用类似默认线程池工厂类类似,指定名称,线程组更多属性。
- 拒绝策略
当线程池的任务缓存队列已满,且线程池的线程数据达到maximumPoolSize 时,如果还会任务来到就会采用配置的拒绝策略,拒绝策略实现 RejectedExecutionHandler 接口,通过查看类结构可以看到线程池提供拒绝策略常用的有以下:
ThreadPoolExecutor.AbortPolicy :丢弃任务并发抛出 RejectedExecutionException 异常 ;ThreadPoolExecutor.DiscardPolicy : 丢弃任务但是不抛出异常
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理改任务 - 线程池简单使用
/** * 异步发送消息 * * @param msgReq * @return */ public static boolean sendMsgAsync(MsgReq msgReq) { threadPoolExecutor.execute(() -> { sendMsgSync(msgReq); }); return true; }
自定义线程池
最新推荐文章于 2024-07-05 09:38:17 发布