一、什么是线程池
线程池其实是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务
二、线程池的作用
线程池可以根据系统的需求和硬件环境灵活地控制线程的数量,且可以对所有线程进行统一的管理和控制,从而提高系统的运行效率,降低系统运行压力
1、线程和任务分离,提升线程重用性
2、控制线程并发数量,降低服务器压力,统一管理所有线程
3、提升系统响应速度(例如创建线程的时间为T1,执行任务时间为T2,销毁线程时间为T3,那么使用线程池后就节省了T1和T3的时间)
三、ThreadPoolExecutor 类
构造方法
public ThreadPoolExecutor(
int corePoolSize, //核心线程数量:如果当前运行的线程数量没有达到 corePoolSize,则新建一个线程,否则加入到任务队列中
int maximumPoolSize, //最大线程数:当前系统最多存在的线程数
long keepAliveTime, //最大空闲时间:线程空闲的最大时间,超出时间该线程会销毁;设置allowCodeThreadTimeOut(true/false),可控制核心线程是否销毁,默认false 表示允许核心线程即使超过最大线程时间也不会销毁
TimeUnit unit, //时间单位: 线程空闲的最大时间的单位
BlockingQueue<Runnable> workQueue, //任务队列: 核心线程数量满了之后,提交的任务加入到队列中,等待核心线程数减少后再去创建线程;当任务队列已满,但没有达到最大线程数时,则新建非核心线程
ThreadFactory threadFactory, //线程工厂: 自定义线程的创建
RejectedExecutionHandler handler //饱和处理机制:当任务队列已满且达到最大线程数时,采取的措施
)
四、线程池工作流程
1、流程图
2、场景描述
1、a客户(任务)去银行办理业务,但银行刚开始营业, 窗口服务员还未就位(相当于线程池中初始线程数量为0),于是经理(线程池管理者)就安排1号工作人员接待客户(创建线程并执行任务)
2、在a客户业务还没办理完时,b客户(任务)又来了,于是经理(线程池管理者)就安排2号工作人员接待b客户(创建新线程并执行任务)
3、假设该银行总共就2个窗口(核心线程数为2)
4、在a、b客户都没有结束的情况下c客户来了,于是经理(线程池管理者)就安排C客户先做到银行大厅的座位上(空位相当于任务队列)等候,当1或2号工作人员空闲后就可以去办理业务
5、假设银行只用1个等候座位(任务队列为1)
6、此时d客户又到了银行,工作人员都在忙,大厅座位也满了,于是经理(线程池管理者)赶紧安排临时工(新创建的线程)在大堂站着给d客户办理业务;
7、 加入前面的业务都没有结束的时候e客户来了,此时正式工作人员、临时工都在满,且座位也满了(正式工作人员加临时工就是最大线程数),于是经理(线程池管理者)只能按照《超出银行最大接待能力处理办法》(饱和处理机制)拒接e客户
8、最后进来办业务的人少了,大厅的临时工空闲时间也超过了1小时(最大空闲时间),经理(线程池管理者)就会让这部分空闲的员工下班(销毁线程);但为了办证银行正常工作(有一个allowCodeThreadTimeOut变量控制是否允许销毁核心线程,默认false),即使正式工闲着,也不提前下班,所有1、2号工作人员继续上班(线程池内保留核心线程;只有当allowCodeThreadTimeOut=true 时销毁核心线程)
五、自定义线程池
1、编写任务类
public class MyTask implements Runnable{
//任务id
private int id;
public MyTask(int id){
this.id=id;
}
@Override
public void run() {
String name=Thread.currentThread().getName();
System.out.println("线程:"+name+"-->即将执行任务"+id);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+name+"执行完成"+id);
}
@Override
public String toString() {
return "MyTask{" +
"id=" + id +
'}';
}
}
2、编写线程类,用于执行任务
public class MyThread extends Thread{
private List<Runnable> tasks;
public MyThread(String name, List<Runnable> tasks){
super(name);
this.tasks=tasks;
}
@Override
public void run() {
while (tasks.size() > 0){
Runnable r= tasks.remove(0);
r.run();
}
}
}
3、编写线程池类,用于管理线程的执行
public class MyThreadPool {
private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
/**
* 当前线程数
*/
private int num;
/**
* 核心线程数
*/
private int corePoolSize;
/**
* 最大线程数
*/
private int maxSize;
/**
* 任务队列数
*/
private int workSize;
public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
/**
* 提交任务
*/
public void submit(Runnable r){
if (tasks.size()>=workSize && tasks.size() > maxSize){
System.out.println("任务:"+r+"被丢弃了");
}else{
tasks.add(r);
execTask(r);
}
}
public void execTask(Runnable r){
if (corePoolSize > num){
new MyThread("核心线程:"+num,tasks).start();
num++;
}else if(num < maxSize){
new MyThread("非核心线程:"+num,tasks).start();
num++;
}else{
System.out.println("任务:"+r+"被缓存了");
}
}
}
4、测试
public class Demo {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(2, 4, 20);
for (int i =0;i< 300;i++){
MyTask myTask = new MyTask(i);
myThreadPool.submit(myTask);
}
}
}