线程池的基本概念
线程池就是存储线程,在高并发的环境下,防止重复创建线程来影响程序性能
优点:
- 提高线程的利用率,重用已经存在的线程,降低线程的创建和销毁造成的消耗。
- 提高程序的响应速度,当任务到达时,通过复用已经存在的线程,无需等待新线程的创建便能立即执行。
- 便于统一管理线程对象,因为如果线程无限制的创建,会导致内存占用过多产生OOM的问题,也会导致CPU切换过度切换,有时间成本
- 可以控制最大并发数等其他高级功能。
线程池的主要参数
- 1.corePoolSize(核心线程数):线程池会维护一个最小的线程数量,核心线程数会一直存活,及时没有任务需要执行。设置allowCoreThreadTimeout=true(默认是false)时,核心线程会超时关闭。
- 2.maximumPoolSize(线程池最大线程数量):一个任务被提交到线程池之后,首先会找有没有空闲的线程,如果有则直接将任务交给空闲线程处理,如果没有就会缓存到工作队列中,如果工作队列满来,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列的尾部,线程池不会无限制去创建新线程,他会又一个最大线程数量的限制,这个限制就是由maximumPoolSize来控制。
- 3.keepAliveTime(空闲存活时间):当创建了多于核心线程数的线程的时候,空闲线程可以通过设置keepAliveTime来使他们过期销毁。
- 4.unit(时间单位):指的是keepAliveTime的时间单位
- 5.ThreadFactory:创建线程的工厂,可以指定线程的名字和是否为守护线程等。
- 6.workQueue:工作队列,就是当任务大于核心线程数的时候缓存的地方。
- 6.1.1:ArrayBlockingQueue:有界的工作队列,底层是数组结构,按照FIFO特性,防止资源耗尽。
- 6.1.2:LinkedBlockingQueue:底层是链表的结构,可以指定大小,不指定大小为Integer.MaxValue,这时候maximumPoolSize参数无用。
- 6.1.3:SynchronousQueue:一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。一一配对的通信策略
- 6.1.4: PriorityBlockQueue:优先队列可以设置优先级,优先级通过参数Comparator实现。
- 7.RejectedExecutionHandler:拒接策略,当工作队列满的时候,且线程池的线程已经达到了maximumPoolSize的时候,就会触发拒绝策略。
- 7.1.1:AbortPolicy:线程池默认的拒绝策略,触发拒绝策略时候会直接跑出RejectedExecutionException异常并直接丢弃。
- 7.1.2:CallerRunsPolicy:在该策略下,在调用者线程中直接执行被拒绝的方法,除非线程池shutdown就直接丢弃。
- 7.1.3:DiscardPolicy:直接丢弃,什么都不做
- 7.1.4:DiscardOldestPolicy:直接丢弃进入队列最老的任务,尝试把刚提交的任务放入队列末尾。
线程池的类型
- 1.newCachedThreadPool:如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
1
2
3
4
5public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
这种类型的线程池特点是:
工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统OOM。
- 2.newFixedThreadPool:指定工作线程数量的线程池
1
2
3
4
5public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。
- 3.newSingleThreadExecutor:
1
2
3
4
5
6public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
4.newScheduleThreadPool:
1
2
3
4public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。
5.newSingleThreadScheduledExecutor:
1
2
3
4public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。线程池中最多执行1个线程,之后提交的线程活动将会排在队列中以此执行并且可定时或者延迟执行线程活动。