首先线程池有什么作用?
- 1.提高响应速度,如果线程池有空闲线程的话,可以直接复用这个线程执行任务,而不用去创建。
- 2.减少资源占用,每次都创建线程都需要申请资源,而使用线程池可以复用已创建的线程。
- 3.可以控制并发数,可以通过设置线程池的最大线程数量来控制最大并发数,如果每次都是创建新线程,来了大量的请求,可能会因为创建的线程过多,造成内存溢出。
- 4.更加方便来管理线程资源。
线程池有哪些参数?
corePoolSize 核心线程数
该线程池中核心线程数最大值,添加任务时,即便有空闲线程,只要当前线程池线程数<corePoolSize,都是会新建线程来执行这个任务。并且核心线程空闲时间超过keepAliveTime也是不会被回收的。(从阻塞队列取任务时,如果阻塞队列为空,核心线程的会一直卡在workQueue.take
方法,被阻塞并挂起,不会占用CPU资源。非核心线程会workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) ,如果超时还没有拿到,下一次循环判断compareAndDecrementWorkerCount就会返回null
,Worker对象的run()
方法循环体的判断为null
,任务结束,然后线程被系统回收)
maximumPoolSize 最大线程数
该线程池中线程总数最大值 ,一般是用于当线程池线程都在执行任务,并且等待队列满了时,如果当前线程数<maximumPoolSize,可以创建一个新线程来执行任务。maximumPoolSize一般也可以用来现在最大线程并发执行量。
workQueue 等待队列
等待队列,一般是抽象类BlockingQueue的子类。
ArrayBlockingQueue | 有界队列,一种使用数组实现的先进先出的有界阻塞队列。支持公平锁和非公平锁,底层数据结构是数组,需要指定队列的大小。 |
---|---|
LinkedBlockingQueue | 无界队列,一种使用链表实现的先进先出的有界阻塞队列。默认的容量是Interge.MAX_VALUE ,相比于ArrayBlockingQueue 具有更高的吞吐量,但是却丢失了随机存储的特性。默认大小是Integer.MAX_VALUE ,也可以指定大小。newFixedThreadPool()和newSingleThreadExecutor()的等待队列都是这个阻塞队列。 |
LinkedBlockingDeque | 一种使用链表实现的具有双向存取功能的有界阻塞队列。在高并发下,相比于LinkedBlockingQueue 可以将锁竞争降低最多一半 |
PriorityBlockingQueue | 一种提供了优先级排序的无界阻塞队列。如果没有提供具体的排列方法,那么将会使用自然排序进行排序,会抛出OOM 异常。 |
SynchronousQueue | 一种不存储任务的同步队列。每一次的插入操作都必须等待其他线程进行相应的删除操作。支持公平锁和非公平锁。同步队列,内部容量为0,每个put操作必须等待一个take操作,反之亦然。newCachedThreadPool()的等待队列都是SynchronousQueue,所以一般都是对于每一个任务都是创建一个新线程去执行。 |
LinkedTransferQueue | 一种使用链表实现的无界阻塞队列。 |
DelayQueue | 一种无界的延时队列,可以设置每个元素需要等待多久才能从队列中取出。 延迟队列,该队列中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素 。一般是用于定时任务线程池newScheduledThreadPool。 |
keepAliveTime:非核心线程闲置超时时长。
非核心线程如果处于闲置状态超过该值,就会被销毁。如果设置allowCoreThreadTimeOut(true),则会也作用于核心线程。
RejectedExecutionHandler 拒绝处理策略
拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略,四种拒绝处理的策略为 :
- ThreadPoolExecutor.AbortPolicy:默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常。
- ThreadPoolExecutor.DiscardPolicy:丢弃新来的任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃等待队列头部(最旧的)的任务,然后重新尝试执行程序,将任务添加到队列中(如果再次失败,重复此过程)。
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。
Executors提供的四种线程池的使用场景。
Executors提供四种线程池,分别为:
newFixedThreadPool 定长线程池
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待(比较适合需要控制并发量的情况)。主要是通过将核心线程数设置为与最大线程数相等实现的。缺点是LinkedBlockingQueue队列的默认长度是Integer.MAX_VALUE,也存在内存溢出的风险。
与CachedThreadPool的区别:
- 因为 corePoolSize == maximumPoolSize ,所以FixedThreadPool只会创建核心线程。 而CachedThreadPool因为corePoolSize=0,所以只会创建非核心线程。
- 在 getTask() 方法,如果队列里没有任务可取,线程会一直阻塞在 LinkedBlockingQueue.take() ,线程不会被回收。 CachedThreadPool会在60s后收回。
- 由于线程不会被回收,会一直卡在阻塞,所以没有任务的情况下, FixedThreadPool占用资源更多。
- 都几乎不会触发拒绝策略,但是原理不同。FixedThreadPool是因为阻塞队列可以很大(最大为Integer最大值),故几乎不会触发拒绝策略;CachedThreadPool是因为线程池很大(最大为Integer最大值),几乎不会导致线程数量大于最大线程数,故几乎不会触发拒绝策略。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
newSingleThreadExecutor 单线程池
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。主要是通过将核心线程数和最大线程数都设置为1来实现。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool可缓存线程池
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。但是由于最大线程数设置的是Integer.MAX_VALUE,存在内存溢出的风险。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
CacheThreadPool
的运行流程如下:
- 提交任务进线程池。
- 因为corePoolSize为0的关系,不创建核心线程,线程池最大为Integer.MAX_VALUE。
- 尝试将任务添加到SynchronousQueue队列。
- 如果SynchronousQueue入列成功,等待被当前运行的线程空闲后拉取执行。如果当前没有空闲线程,那么就创建一个非核心线程,然后从SynchronousQueue拉取任务并在当前线程执行。
- 如果SynchronousQueue已有任务在等待,入列操作将会阻塞。
当需要执行很多短时间的任务时,CacheThreadPool的线程复用率比较高, 会显著的提高性能。而且线程60s后会回收,意味着即使没有任务进来,CacheThreadPool并不会占用很多资源。
newScheduledThreadPool定时执行线程池
创建一个定时执行的线程池,主要是通过DelayedWorkQueue来实现(该队列中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素)。支持定时及周期性任务执行。但是由于最大线程数设置的是Integer.MAX_VALUE,存在内存溢出的风险。
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
原创文章,作者:9IM,如若转载,请注明出处:https://www.9im.cn/741.html
评论列表(2条)
感觉这主题不适合阅读,读起来有点费劲
haha,看得人也比较少