线程池的有点:省时、省资源、更好管理线程
1、减少资源的消耗:较少线程创建和销毁造成的消耗
2、提高响应速度:当任务到达的时候,就能够立刻执行,减少了线程创建和销毁的时间
3、能够更好地管理线程
ThreadPoolExecutor 的类关系
Executor:接口,是线程池的基础,将任务的提交与任务的执行分离开来。
ExecutorService:接口:继承了Executor,新加了shutdown(),submit()
AbstractExecutorService:实现了ExecutorService大部分方法,可以少写很多代码
ThreadPoolExecutor:线程池的核心实现了,用来执行被提交的任务
ScheduledExecutorService:提供了带周期执行的ExecutorService
ScheduledThreadPoolExecutor:可以延迟执行任务
线程池的创建各个参数含义
完整的构造函数
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize
线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到线程数=corePoolSize,之后提交的任务会被保存到阻塞队列中,等待被执行。
备注:如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建好corePoolSize数量的线程,提高效率
maximumPoolSize
如果线程数=corePoolSize,且阻塞队列也被塞满了,这个时候再提交任务,就会再创建线程执行任务,但是线程池总线程数必须<=maximumPoolSize
keepAliveTime
当线程数>corePoolSize时,当前线程没有任务执行,线程继续存活的时间
线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间。默认情况下,该参数只在线程数大于corePoolSize时才有用
TimeUnit
keepAliveTime线程存活的时间单位
关于小时的常用方法
TimeUnit.HOURS.toMillis(1) | 1小时转分 |
TimeUnit.HOURS.toMinutes(60) | 60小时转分 |
TimeUnit.HOURS.sleep(5) | 线程休眠5秒 |
TimeUnit.HOURS.convert(1, TimeUnit.MINUTES) | 1小时转秒 |
常用工具类
TimeUnit.DAYS | 日的工具类 |
TimeUnit.HOURS | 时的工具类 |
TimeUnit.MINUTES | 分的工具类 |
TimeUnit.SECONDS | 秒的工具类 |
TimeUnit.MILLISECONDS | 毫秒的工具类 |
workQueue
workQueue必须是BlockingQueue阻塞队列:当线程池的线程数超过corePoolSize的时候,多余的线程就会进入阻塞队列中,等待被执行
应当尽量使用有界阻塞队列,比如:LinkedBlockingQueue、ArrayBlokngQueue、SynchronousQueue、PriorityBlockingQueue,使用无界阻塞队列(比如:DelayQueue、LinkedtransferQueue)会产生如下影响
1、当线程数超过corePoolSize之后,其他线程就会放在无界队列中等待,就不会再创建新的线程来执行任务了,导致界队列时maximumPoolSize将是一个无效参数。
2、由于1,使用无界队列的keepAliveTime参数无效
3、无界队列可能会耗尽系统资源
threadFactory
创建线程的工厂,使用场景
1、通过自定义的线程工厂,给每个新建的线程设置一个有识别度的线程名
2、通过线程工厂把所有的线程设置为守护线程
demo
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
20,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
//1、设置线程的名字
Thread thread = new Thread(r);
//thread.setName("通过自定义线程工厂谁知线程名字");
//2、设置成守护线程
//thread.setDaemon(true);
return thread;
}
},
// new ThreadPoolExecutor.CallerRunsPolicy());
// new ThreadPoolExecutor.DiscardOldestPolicy());
// new ThreadPoolExecutor.DiscardPolicy());
new AbortPolicy());
}
}
RejectedExecutionHandler
当阻塞队列被塞满了,并且没有多余的线程执行任务的时候,对于新添加进来的任务必须做一个处理
AbortPolicy | 默认:直接抛异常 |
CallerRunsPolicy | 用调用者线程来执行(比如main) |
DiscardOldestPolicy | 丢掉队列中最靠前的任务,并执行当前任务 |
DiscardPolicy | 直接丢掉任务 |
实现RejectedExecutionHandler | 日志记录或者持久化存储 |
demo
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
20,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
//1、设置线程的名字
Thread thread = new Thread(r);
//thread.setName("通过自定义线程工厂谁知线程名字");
//2、设置成守护线程
//thread.setDaemon(true);
return thread;
}
},
// new ThreadPoolExecutor.CallerRunsPolicy());
// new ThreadPoolExecutor.DiscardOldestPolicy());
// new ThreadPoolExecutor.DiscardPolicy());
new AbortPolicy());
}
}