为何要使用线程池?java
1.频繁的建立、销毁线程伴随着系统开销,会在很大程度上影响系统性能,效率会下降;并发
2.线程并发数量过大的状况下,线程直接抢占资源会致使系统阻塞;函数
3.线程池会对线程进行一些简单的管理。性能
实现学习
在java中管理线程的是java.util.concurrent包下的Executor接口。这个接口的具体实现类是ThreadPoolExecutor类。学习线程的话,主要是对这个类的构造函数进行一些配置。spa
ThreadPoolExecutor的构造函数线程
构造函数参数的不一样又分为四个构造函数(有5个参数的,6个参数的,7个参数的),后面会具体讲解,请往下看。对象
构造函数中各个参数的意义接口
1.队列
int corePoolSize 该线程池中核心线程的数的最大值,线程池在新建线程的时候,若是当前的线程总数小于corePoolSize,则新建的是核心线程。
2.
int maximumPoolSize 该线程池中线程总数的最大值,线程总数=核心线程数+非核心线城数。
3.
long keepAliveTime 该线程池中非核心线城闭置状态下起始时长,一个非核心线城,若是闭置状态下的时长超过这个参数设定的时长,就会被销毁。
4.
TimeUnit unit 就是一个枚举类型
5.
BlockingQueue<Runnable> workQueue 2该线程池中的任务队列,维护着等待的对象,当全部的核心线城都在干活时,新添加的任务会到这个队列中等待被处理,若是队列满了,就会建立非核心线程执行任务。
6.
ThreadFactory threadFactory 建立线程的方式,这是一个接口
7.
RejectedExecutionHandler handler 抛异常专用,若是有错误产生,则由handler抛出
经常使用的4种线程池(根据业务场景选择)
1. CachedThreadPool()
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
根据源码能够看出这种线程池是没有核心线程的,在建立任务时,如有空闲的线程则复用,不然就建立一个新的线程,没有工做的线程,超过60s就会被销毁。
2.FixedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
经过源码能够看出该线程池的最大线程数等于核心线程数,因此该线程池的的线程不会由于闭置状态起时被销毁。若是当前线程数小于核心线程,不会去复用以前的线程,会建立新的线程去执行任务;若是当前执行任务大于该线程的核心线程数,大于的任务会在队列中等待。
3.SingleThreadPool()
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
仅有一个工做线程执行任务,全部的任务遵循队列的入队出队规则
4.SchdeledThreadPool()
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler); }
设置了最大线程数,核心线程数。这个线程是惟一一个有延迟执行和周期执行任务的线程池。