线程池的好处
1.重复利用已创建的线程降低线程创建和销毁造成的消耗
2.当任务到达,可以不需要创建线程就立即执行
3.提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程可以进行统一分配,调优和监控
线程池的实现原理
当向线程池提交一个任务之后,线程池的处理流程如下
1.线程池判断核心线程池里的线程是否都在执行任务,如果不是,则创建一个新的工作线程来执行任务。如果是核心线程里的线程都在执行任务,则进入下一个流程
2.线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3.线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
注意:核心线程池和线程池里面的线程数量不一致
threadPoolExecutor执行execute方法
1.如果当前运行的线程少于corePoolSize,则创建新线程来执行任务。
2.如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
3.如果BlockingQueue满了,则创建新的线程来处理任务
4.如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法
线程池的参数
1.corePoolSize(核心线程数):,当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。
2.runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。阻塞队列有:
ArrayBlockingQueue:基于数组结构的有界阻塞队列,
LinkedBlockingQueue:基于链表结构的阻塞队列。吞吐量高于数组
SynchronousQueue:一个不存储元素的阻塞队列。每个插入必须等待另外一个线程调用移除操作,否则插入一直阻塞,吞吐量高于链表。
3.maximumPoolSize(线程池最大数量):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果使用了无界的任务队列这个参数就没有什么效果
4.threadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置名称。
5.RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,采取拒绝策略:
AbortPolicy:直接抛出异常
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃掉队列里最近的一个任务,并执行当前任务。
DiscardPolicy:不处理,丢弃掉
6.keepAliveTime:线程池的工作线程空闲后,保持存活的时间
7.TimeUnit:线程活动保持时间的单位
线程池提交任务的两种方式
public void execute(Runnable command)方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。
public Future<?> submit(Runnable task)方法用于提交需要返回值的任务,线程池会返回一个future类型的对象,通过这个对象来判断任务是否执行成功,并且可以通过future的get方法来获取返回值,get方法会阻塞当前线程知道任务完成。