线程池
概念介绍:
1.1什么是线程池
线程池其实就是多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建在创建线程后自动启动这些任务。这里的线程就是我们之前学过的线程,这里的任务就是我们前面学过的实现了Runnable或Callable接口的实例对象
1.2为什么使用线程池
使用线程池最大的原因就是可以根据系统的需求和硬件环境灵活的控制线程的数量,且可以对所有线程进行统一的管理和控制,从而提高系统运行效率,降低系统运行压力;当然了,使用线程池的原因不仅仅只有这些,我们可以从线程池自身的优点上来进一步了解线程池的好处。
1.3使用线程池有哪些优势
1:线程和任务是分离的,提升线程重用性
2:控制线程并发数量,降低服务器压力,统一管理所有线程
3:提升系统响应速度,假如创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间
1.4线程池应用场景
应用场景介绍:
1:网购商品秒杀
2:云盘文件上传和下载
3:12306网上购票
总结:
只要有并发的地方,任务数量大或小,每个任务执行时间长或短的都可以使用线程池,只不过在使用线程池的时候注意一下设置合理的线程大小。
2:线程池的使用
2.1:Java内置线程池介绍
我们要想自定义线程池,必须了解线程池的工作原理,才能自己定义线程池;观察ThreadpoolExecutor的源码学习线程池原理
构造方法
public ThreadPoolExecutor(int corePoolSize, 核心线程数量
int maximumPoolSize, 最大线程数 当核心线程满 任务队列满 会创建线程,数量小于最大线程
long keepAliveTime, 最大空闲时间 没有任务执行的时候 空闲到一定时间回收线程
TimeUnit unit, 时间单位
BlockingQueue<Runnable> workQueue, 任务队列 相当于临时缓冲区
ThreadFactory threadFactory, 线程工厂
RejectedExecutionHandler handler 饱和处理机制 任务队列满 线程数量满 处理的方法
) {
…
}
2.2自定义线程池----参数设计分析
2.2.1:4个参数的设计
1:核心线程数(corePoolSize)
核心线程数的设计需要依据任务的处理时间和每秒产生的任务数量来确定
2:任务队列长度(workQueue)
任务队列长度一般设计为:核心线程数/单个任务执行时间*2即可,
3:最大线程数量(maximumPoolSize)
最大线程数的设计需要参照核心线程数的条件外,还需要参照系统每秒产生的最大任务数决定,最大线程数=(最大任务数-任务队列长度)*单个任务执行时间
4:最大空闲时间(keepAliveTime)
根据系统决定
2.2自定义线程池----实现步骤
1:编写任务类实现Runnable接口
2:编写线程类,用于执行任务,需要持有所有任务
3:编写线程池类,包含提交任务,执行任务的能力
4:编写测试类,创建线程池对象提交多个任务测试
package 线程池;
/*
* 自定义线程池练习
* 包含任务编号,每一个任务执行时间设计为0.2s
* */
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+"即将执行任务");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+name+"完成任务");
}
@Override
public String toString() {
return "MyTask{" +
"id=" + id +
'}';
}
}
package 线程池;
import java.util.List;
/*
* 编写一个线程类继承Thread,设计一个属性,用于保存线程的名字
* 设计一个集合,用于保存所有的任务*/
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 r = tasks.remove(0);
r.run();
}
}
}
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/*自定义线程池
1;任务队列 集合 需要控制线程安全问题
2:统计当前线程数量
3:核心线程树
4;最大线程数
5:任务队列长度
成员方法:
1:提交方法:将任务添加到集合,需要判断是否超出了任务总长度
2:执行任务: 判断当前线程数量,决定创建核心线程还是非核心线程
* */
public class MyThreadPool {
private List<Runnable> task = Collections.synchronizedList(new LinkedList<>());
//当前线程数量
private int num;
private int corePoolSize;
private int maxSize;
//任务队列长度
private int workSize;
//提交i任务
public void submit(Runnable r){
if(task.size()>=workSize){
System.out.println("任务"+r+"被丢弃了。。。");
}else {
task.add(r);
//执行任务
execTask(r);
}
}
//执行任务
private void execTask(Runnable r) {
if(num < corePoolSize){
new MyWorker("核心线程"+num,task).start();
num++;
}else if(num < maxSize){
new MyWorker("非核心线程"+num,task).start();
}else {
System.out.println("任务:"+r+"被缓存了。。。");
}
}
public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
}
package 线程池;
/*
* 1;创建线程池类
* 2:提交多个任务*/
public class MyTest {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(2,4,20);
//提交多个任务
for(int i = 0; i < 30; i++){
//创建任务对象并提交给线程池
MyTask my = new MyTask(i);
myThreadPool.submit(my);
}
}
}
2.3 java内置线程池–ExecutorService
ExecutorService接口是java内置线程池接口。
void shutdown()启动一次顺序关闭,执行以前提交的任务,但不接受新任务
List shutdownNow()停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务队列
Future submit(Callable task)执行带返回值的任务,返回一个Future对象
Future<?>submit(Runnable task) 执行Runnable任务,并返回一个表示该任务的Future
Futuresubmit(Runnable task,T result)执行Runnable任务,并返回一个表示该任务的Future
获取ExecutorService可以利用JDK中的Executors类中的静态方法,常用获取方式如下:
static ExecutorService newCachedThreadPool() 创建一个默认的线程池对象,里面的线程池可重用,且在第一次使用时才创建
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) 线程池中所有的线程都使用ThreadFactory来创建,这样的线程无需手动启动,自动执行
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池
static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory) 创建一个可重用固定线程数的线程池且线程池中所有的线程都是用ThreadFactory来创建
static ExecutorService newSingleThreadExecutor() 创建一个使用单个worker线程的Executor,以无界队列来运行该程序
static ExecutorService newSingleThreadExecuor(ThreadFactory threadFactory) 创建一个使用单个worker线程的Executor,且线程池中所有的线程都是用ThreadFactory来创建
package 内置线程池;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/*
* 练习Executors获取ExecutorService,然后调用方法执行任务*/
public class MyTest01 {
public static void main(String[] args) {
//1.使用工厂类获取线程池对象
// ExecutorService es = Executors.newCachedThreadPool();
ExecutorService es = Executors.newCachedThreadPool(new ThreadFactory() {
int n = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"自定义的线程名称"+n++);
}
});
//2.提交任务
for(int i=0; i < 10 ; i ++){
es.submit(new MyRunnable(i));
}
}
}
class MyRunnable implements Runnable{
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了任务..."+id);
}
}
ScheduledExecutorService是ExecutorService的子接口,具备了延迟运行和定期执行人物的能力
常用获取方式如下:
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个可重用固定线程数的线程池且允许延迟运行或定期执行任务
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建,且允许延迟允许或定期执行任务
static ScheduledExecutorService newSingleThreadScheduledExecutor() …
static ScheduledExecutorService new SingleThreadScheduledExecutor(ThreadFactory threadFactory) …
ScheduledExecutorService常用方法如下:
ScheduledFuture schedule(Callable callable,long delay,TimeUnit unit) 延迟时间单位是unit,数量是delay的时间后执行callable
ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit) 延迟单位是unit,数量是delay的时间后执行command
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long initialDelay,long period,TimeUnit unit)延迟时间单位是unit,数量是initialDelay的时间后,每间隔period时间重复执行一次command
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟
package ScheduleExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduleExecutorServiceDemo01 {
public static void main(String[] args) {
//获取一个具备延迟执行任务的线程池对象
ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
//2创建多个任务对象,提交任务,每个任务延迟两秒
es.schedule(new MyRunnable(1),2000, TimeUnit.MILLISECONDS);
System.out.println("over");
}
}
class MyRunnable implements Runnable{
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了任务"+id);
}
}