首先,让我们问一个问题,为什么要使用线程池?很多时候,我们使用多线程来执行任务的时候都是这样一个场景:每新建一个任务就对应地创建一个线程,而往往每个任务在很短的时间内就结束了,导致线程的创建和销毁频繁发生,这会降低系统的效率。线程池的应用便应运而生。
一,Java线程池
1,ThreadPoolExecutor
ThreadPoolExecutor是线程池任务执行器。其继承链为
ThreadPoolExecutor extends AbstractExecutorService implements ExecutorServiceextendsExecutor
ThreadPoolExecutor的几个重要构造参数包括以下:
1)corePoolSize:核心池尺寸,当池大小小于corePoolSize时,就新建线程来执行任务。当池大小等于corePoolSize时,就将任务放进workQueue阻塞队列。池子中的空闲线程去队列中获取任务来执行。
2)maximumPoolSize:最大池尺寸,当队列已经满了,就新建线程入池来处理请求,但是线程数量不能超过最大池尺寸。
3)keepAliveTime:线程存活时间,决定当一个线程空闲了多长时间后被销毁。只有在线程池尺寸大于corePoolSize时才起作用。
4)unit:时间单位,有7种选择:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
5)workQueue:阻塞队列,用来存储待执行的任务。声明类型为BlockingQueue<Runnable>,有以下几种选择:
ArrayBlockingQueue |
基于数组,先进先出,必须指定大小 |
LinkedBlockingQueue |
基于链表,先进先出,如未指定大小,则为Integer.MAX_VALUE |
SynchronousQueue |
没有尺寸的概念,不会保存提交的任务,而是将直接新建一个线程来执行新来的任务 |
PriorityBlockingQueue |
其存储的对象必须实现Comparable接口,队列根据compare接口方法确定任务的优先级 |
常用的是LinkedBlockingQueue和SynchronousQueue
6)threadFactory,线程工厂,用来创建线程。
7)handler,拒绝处理任务时的策略,包括
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:丢弃任务,不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
ThreadPoolExecutor的几个重要方法
1)execute()
向线程池提交任务,交由线程池来执行
2)submit()
同样是向线程池提交任务,其内部调用了execute(),区别是,会返回一个FutureTask实例
3)shutdown()
等任务都执行完毕后关闭线程池,并且拒绝接受新的任务
4)shutdownNow()
停止正在执行的任务,立刻关闭线程池,拒绝接受新的任务
5)isTerminated()
检查线程池是否已关闭
代码示例:
任务类
package com.wxy.popcorn.threadpool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Task implements Runnable {
priv