什么是线程池
线程池是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后创建线程后自动启动这些任务。这里的线程就是我们在前面学过的线程,这里的任务就是实现了Runnale和Callable接口的实例对象。
为什么使用线程池
使用线程池的最大原因是可以根据系统的需求和硬件环境灵活的控制线程数量,且可以对所有线程进行统一的控制和管理,从而提高系统的运行效率,降低系统运行运行压力,使用线程池的原因不仅仅只有这些,我们可以用线程池自身的优点上来进一步了解线程池的好处。
线程池的优点
线程和任务分离,提升线程重用性
控制线程并发数量,降低服务器压力,统一管理所有线程。
提升系统的响应速度,假如创建了线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么线程池就免去了T1和T3的时间。
线程池应用场景
网购商品介绍
云盘文件上传和下载
12306网上购票系统
只要有并发的地方,任务数量大或者小,每个任务执行时间长和短都可以使用线程池,只不过在使用线程池的时候,注意一下设置合理的线程池大小即可。
ThreadPoolExcutor
从jdk1.5版本开始
构造方法
线程池运行流程
参数设计分析
不难发现,如果想要设计一个好的线程池,就必须合理设置线程池的四个参数。
核心线程数 corePoolSize
任务队列长度 workingQueue
最大线程数 maximumPoolSize
最大空闲时间
自定义线程池
1)编写任务类,实现runnable接口
2)编写线程类,用于执行任务,需要持有所有任务
3)编写线程池,包括提交任务,执行任务的能力在这里插入代码片
4)编写测试类,创建线程池对象,提交多个任务测试
MyTask任务类
package com.mmz;
/**
* @Classname MyTask
* @Description 任务类,包含任务编号,每一个任务的执行时间为0.2s
*
* @Date 2020/4/23 0:21
* @Created by mmz
*/
public class MyTask implements Runnable{
private int id;
//由于run方法是重写接口中的方法,因此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 +
'}';
}
}
MyWorker 线程类
package com.mmz;
import java.util.List;
/**
* @Classname MyWorker
* @Description 编写一个线程类,需要继承Thread类,设计一个属性,用于保存线程的名字,设计一个集合,用于保存所有的任务
* @Date 2020/4/23 0:26
* @Created by mmz
*/
public class MyWorker extends Thread{
private String name;//保存线程的名字
private List<Runnable> tasks;
public MyWorker(String name, List<Runnable> tasks) {
super(name);
this.tasks = tasks;
}
@Override
public void run(){
//判断集合是否有任务
while(tasks.size()>0){
Runnable runnable = tasks.remove(0);
runnable.run();
}
}
}
MyThrealPool
package com.mmz;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @Classname MyThreadPool
* @Description 自定义的线程池类
* 成员变量
* 1.任务队列 集合 需要控制线程安全问题
* 2.当前线程数量
* 3.核心线程数
* 4.最大线程数
* 5.任务队列长度
* 成员方法
* 1.提交方法,将任务添加入集合,需要判断是否超出了任务的总长度
* 2.执行任务,判断当前线程的数量,决定创建核心线程和非核心线程
*
* @Date 2020/4/23 0:30
* @Created by mmz
*/
public class MyThreadPool {
//1.任务队列 集合 需要控制线程安全问题
private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
//2.当前线程数量
private int num;
//3.核心线程数
private int corePoolSize;
//4.最大线程数
private int maxSize;
//5.任务队列长度
private int workSize;
//1.提交任务
public void submit(Runnable runnable){
//判断当前集合中任务的数量是否超出了最大任务数量
if(tasks.size()>=workSize){
System.out.println("任务"+runnable+"被丢弃了");
}else{
tasks.add(runnable);
execTask(runnable);
}
}
//执行任务
private void execTask(Runnable runnable) {
//判断当前线程中的线程总数量,是否超出了核心数。
if(num < corePoolSize){
new MyWorker("核心线程"+num,tasks).start();
num++;
}else if(num < maxSize){
new MyWorker("非核心线程"+num,tasks).start();
num++;
}else{
System.out.println("任务"+runnable+"被缓存起来了");
}
}
public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
}
MyTest 测试类
package com.mmz;
/**
* @Classname MyTest
* @Description 创建线程池类,提交多个任务,
* @Date 2020/4/23 0:42
* @Created by mmz
*/
public class MyTest {
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(2,4,20);
//提交多个任务
for(int i = 0;i<10;++i){
//创建任务对象,提交给线程池
MyTask myTask = new MyTask(i);
pool.submit(myTask);
}
}
}