多线程-线程池的7个参数及其作用
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;}
参数说明<1>第一个参数:corePolSize线程池将维护一个线程数量最小,即使这些线程处于空闲状态,除非设置了allowcorethreadtimeout,否则它们也不会被销毁。这里的最小线程数量是corepolsize。这个参数设置非常关键。设置过度浪费资源,设置过小导致线程频繁创建或销毁。
<2>第2个参数:maximumPoolSize 任务提交到线程池后,首先会发现是否有空闲生存线程。如果是这样,它将直接执行。如果没有,它将被执行缓存到工作队列在中间,如果工作队列满了,将创建一个新的线程,然后从工作队列的头部取出一个任务,并将刚刚提交的任务放在工作队列的尾部。线程池不会无限制地创建新的线程,它会有最大线程数量的限制,这个数量是由maximunPolsize的数量减去corePolsize的数量来确定的,最多可以达到maximunPolsize,即最大线程池的线程数量。
<3>第三个参数:keepalivetime表示线程池中的线程空闲时间,当空闲时间达到keepalivetime值时,线程将被销毁,直到只剩下corepolsize线程,以避免浪费内存和句柄资源。
<4>第4个参数: TimeUnit表示时间单位。keepAliveTime 时间单位通常是TimeUnittt.SECONDS。
<5>第5个参数: workQueue 表示缓存队列。当要求的线程数大于corePolsize时,线程进入blockingQueue阻塞队列。
<6>第6个参数: threadFactory 表示线程工厂。它是用来表示的。生产一组相同任务的线程。通过在factory中添加组名前缀来实现线程池的命名。在虚拟机栈分析中,您可以知道线程任务是由哪个线程工厂生成的。
<7>第7个参数: handler 表示执行拒绝策略对象。当第五个参数workQueue的任务缓存区上限超过时,可以通过该策略处理请求,这是一种简单的限流保护。
Java线程池的四种拒绝策略 (1)拒绝时机<1>第一种情况是我们调用它 shutdown 关闭线程池后,即使线程池内仍有未完成的任务,由于线程池已关闭,如果此时向线程池提交任务,也将被拒绝。
<2>第二种情况是线程池无法继续处理新提交的任务,也就是工作已经很饱和的时候。
(2)拒绝策略<1>第一种是 AbortPolicy(默认)当拒绝任务时,这种拒绝策略会直接抛出一种类型 RejectedExecutionException 的 RuntimeException,让您感觉到任务被拒绝了,因此您可以根据业务逻辑选择重试或放弃提交等策略。
<2>第二种是 DiscardPolicy,这种拒绝策略就像它的名字所描述的那样,当新任务被直接丢弃时,它不会给你任何通知,因为我们不知道任务会被丢弃,这可能会导致数据丢失。
<3>第三种是 DiscardOldestPolicy,如果线程池未关闭且无法执行,则任务队列中的头结点将被丢弃,这通常是生存时间最长的任务。这一策略与第二个策略不同的是,它丢弃的不是最新提交的,而是队列中生存时间最长的,因此可以为新提交的任务腾出空间,但同样,也存在一定的数据丢失风险。
<4>第四种是 CallerRunsPolicy,相对而言,它是比较完美的,当有新的任务提交时,如果线程池未关闭,无法执行,将此任务交给提交任务的线程执行,即谁提交任务,谁负责执行任务。这样做有两个主要的好处:
①第一点新提交的任务不会丢弃,不会造成业务损失。 ②第二个好处是,由于任何提交任务的人都必须负责执行任务,因此提交任务的线程必须负责执行任务,而执行任务相对耗时。在此期间,提交任务的线程被占用,因此不会提交新任务,这减缓了提交任务的速度,相当于负面反馈。在此期间,线程池中的线程也可以充分利用这段时间执行部分任务,腾出一定的空间,相当于给线程池一定的缓冲期。