一、线程池基础
-
什么是线程池
线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。
-
为什么使用线程池
可以根据系统的需求和硬件环境灵活的控制线程的数量,且可以对所有线程进行统一管理和控制,从而提高系统的运行效率,降低系统运行压力
-
线程池有哪些优势
1)线程和任务分离,提升线程重用性
2)控制线程并发数量,降低服务器压力,统一管理所有线程
3)提升系统响应速度,假设创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间 -
线程池应用场景介绍
1)应用场景介绍
网购商品秒杀
云盘文件上传和下载
12306网上购票系统等2)总之
只要有并发的地方,任务数量大或者小,每个任务执行时间长或短都可以使用线程池,只不过在使用线程池的时候,注意一下设置合理的线程池大小即可
二、线程池使用
1.java内置线程池
1.1 Java内置线程池原理剖析
//ThreadPoolExecutor源码分析
public ThreadPoolExecutor(int corePoolSize,//核心线程数量
int maximumPoolSize,//最大线程数
long keepAliveTime,//最大空闲时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列
ThreadFactory threadFactory,//线程工厂
RejectedExecutionHandler handler//饱和处理机制) {
...
}
1.2 线程池工作流程总结示意图
2.自定义线程池
2.1 四个参数设计分析
-
核心线程数——corePoolSize
核心线程数的设计需要依据任务的处理时间和每秒产生的任务数量来确定。一般按照8020原则设计即可,即按照80%的情况设计核心线程数,剩下20%可以利用最大线程数处理 -
任务队列长度——workQueue
任务队列长度一般设计为:核心线程数/单个任务执行时间*2即可 -
最大线程数——maximumPoolSize
最大线程数的设计除了需要参照核心线程数的条件外,还需要参照系统每秒产生的最大任务数决定。
-
最大线程数=(最大任务数-任务队列长度)*单个任务执行时间
-
最大空闲时间——keepAliveTime
这个参数的设计完全参考系统运行环境和硬件压力设定
2.2 java内置线程池
/**
ExecutorService介绍
ExecutorService接口是java内置的线程池接口,通过学习接口中的方法,可以快速的掌握java内置线程池的基本使用
常用方法
*/
void shutdown();//启动一次顺序关闭,执行以前提交的任务,但不接受新任务
List<Runnable> shutdownNow();//停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务列表
<T> Future<T> submit(Callable<T> task);//执行带返回值的任务,返回一个Future对象
<T> Future<T> submit(Runnable task, T result);//执行Runnable任务,并返回一个表示该任务的Future
Future<?> submit(Runnable task);//执行Runnable任务,并返回一个表示该任务的Future
/**
获取ExecutorService可以利用JDK中的Executors类中的静态方法,常用获取方式如下
*/
//创建一个默认的线程池对象,里面的线程可重用,且在第一次使用时才创建
static ExecutorService newCachedThreadPool()
//线程池中的所有线程都使用ThreadFactory来创建,这样的线程无需手动启动,自动执行
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
//创建一个可重用固定线程数的线程池
static ExecutorService newFixedThreadPool(int nThreads)
//创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
//创建一个使用单个worker线程Executor,以无界队列方式来运行该线程
static ExecutorService newSingleThreadExecutor()
//创建一个使用单个worker线程Executor,且线程池中的所有线程都使用ThreadFactory来创建
static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
/**
ScheduledExecutorService介绍
ScheduledExecutorService是ExecutorService的子接口,具备了延迟运行或定期执行任务的能力
常用获取方式如下:
*/
//创建一个可重用固定线程数的线程池且允许延迟运行或定期执行任务
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
//创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建,且允许延迟运行或定期执行任务
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
//创建一个单线程执行程序,它允许在给定延迟后运行命令或者定期地执行
static ScheduledExecutorService newSingleThreadScheduledExecutor()
//创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行
static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
/**
ScheduledExecutorService常用方法如下
*/
//延迟时间单位是unit,数量是delay的时间后执行callable
<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
//延迟时间单位是unit,数量是delay的时间后执行command
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
//延迟时间单位是unit,数量是initialDelay的时间后,每间隔period时间重复执行一次command
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
long period, TimeUnit unit);
//创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
long delay, TimeUnit unit);
2.3异步计算结果(Future)
Future接口就是专门用于描述异步计算结果的,我们可以通过Future对象获取线程计算的结果;
/**
Future的常用方法如下
*/
//试图取消对此任务的执行
boolean cancel(boolean mayInterruptIfRunning);
//如有必要,等待计算完成,然后获取其结果
V get()
//如果必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)
V get(long timeout, TimeUnit unit)
//如果在任务正常完成前将其取消,则返回true
boolean isCancelled();
//如果任务已完成,则返回true
boolean isDone();