线程池详解

文章介绍了Java中线程池的概念和重要性,包括通过Executors创建线程池的不同方式,如单线程、固定大小、可缓存和定时线程池。文章还详细讲解了线程池的核心参数,如核心线程数、最大线程数、空闲线程存活时间和工作队列,以及线程池的四种拒绝策略。最后指出直接使用Executors创建线程池可能存在的风险,并建议使用ThreadPoolExecutor直接构造线程池以获取更多控制。
摘要由CSDN通过智能技术生成

目录

一. 前言

二. 快速创建线程池

三. 线程池核心参数


一. 前言

线程池可以看做是线程的集合。它的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后 启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕, 再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程。

类结构关系:

二. 快速创建线程池

Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。

1. 创建单线程的线程池

public static ExecutorService newSingleThreadExecutor()

源码实现:

new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, 
                                new LinkedBlockingQueue<Runnable>());

2. 创建固定数目线程的线程池

public static ExecutorService newFixedThreadPool(int nThreads)

源码实现:

new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());

3. 创建可缓存的线程池

public static ExecutorService newCachedThreadPool()

将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。

源码实现:

new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());

4. 创建支持定时及周期性的任务执行的线程池

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

多数情况下可用来替代Timer类

源码实现:

new ScheduledThreadPoolExecutor(corePoolSize);

public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor 
                            implements ScheduledExecutorService {
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
}

Executors只是对线程池一些特定情况的简洁使用,在生产场景被很多企业的开发规范所禁用。因为会有内存溢出的风险,直接用ThreadPoolExecutor构造线程池会获得更为强大的功能。

newSingleThreadExecutor,newFixedThreadPool阻塞队列LinkedBlockQueue的初始容量为int.MAX_VALUE
newCachedThreadPool,newScheduledThreadPool 最大线程数为int.MAX_VALUE

三. 线程池核心参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

1. corePoolSize 线程池核心线程数

线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。任务提交到线程池后,首先会检查当前线程数是否达到了corePoolSize,如果没有达到的话,则会创建一个新线程来处理这个任务。

2. maximumPoolSize 线程池最大线程数

当前线程数达到corePoolSize后,如果继续有任务被提交到线程池,会将任务缓存到工作队列(后面会介绍)中。如果队列也已满,则会去创建一个新线程来处理。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。

3. keepAliveTime 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定

4. unit 空闲线程存活时间单位

keepAliveTime的计量单位,可以是秒,豪秒,纳秒

5. workQueue 工作队列

核心线程数满后,新的任务会进入到此工作队列中,任务调度时再从队列中取出任务。

JDK提供了4种工作队列:ArrayBlockingQueue、LinkedBlockingQuene、SynchronousQuene、PriorityBlockingQueue

6. threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。

7. handler 拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:

7.1. DiscardPolicy

默认策略,直接丢弃任务,且不抛出异常。

7.2. AbortPolicy

直接丢弃任务,并抛出RejectedExecutionException异常。

7.3. CallerRunsPolicy

在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

7.4. DiscardOldestPolicy

抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列。

7.5. 自定义策略

实现接口RejectedExecutionHandler,自定义拒绝策略。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流华追梦

你的鼓励将是我创作最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值