线程池
1.池:现实世界中的池子都是一个类似水塘的大坑,而今天我们要讲的线程池,类比理解就是一个存储线程的池子
2.为什么要用线程池:
- 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
- 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
- 线程池:就是一个里面都是线程的池塘,类比理解图:01-水池.jpg, 02-沙池.jpg ,03-线程池.png
- java中怎样使用线程池:Executors类是JDK 1.5开始自带的一个非常强大的主要用于创建各类线程池的工具类
3.创建线程池:Executors.newCachedThreadPool: 方法用于创建线程数数目可以随着实际情况自动调节的线程池
- 补充导读:这种线程池的最大线程数只受到操作系统可以创建的最大线程数数目限制,当线程池有很多任务需要处理时,会不断地(自动)创建新线程,
- 当任务处理完毕之后,
- 如果某个线程空闲时间大于60s,则该线程将会被销毁。因为这种线程池能够自动调节线程数量,所以比较适合执行大量的短期的小任务
- 相当于是现实世界中的一种“变色龙”的感觉
代码实例: ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
扩展导读:https://www.cnblogs.com/zhujiabin/p/5404771.html
- newCachedThreadPool
- 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool
- 创建一定数量的线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool
- 创建一个定长线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor
- 创建一个单线程化的线程池(例如火车安检的时候),它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
4.将线程加入到线程池中实现管理:
代码实例: newCachedThreadPool.execute(runnable() );
5.线程池使用的场景:线程池---->netty框架---->Dubbo,Zookeeper,RocketMQ
1.1.newFixedThreadPool 固定大小的线程池 例子
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
package com.Li.xcchi; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Description: 利用线程池newFixedThreadPool实现多线程 * @auther:Li Ya Hui * @Time:2021年4月22日下午12:28:21 */ public class Test { public static void main(String[] args) { //通过Executors 创建一个 newFixedThreadPool线程池 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10); //利用线程池创建多线程 for (int i = 0; i < 10; i++) { if (!fixedThreadPool.isShutdown()) { //内部类 实例runnable fixedThreadPool.submit(new Runnable() { @Override public void run() { try { //线程睡眠 Thread.sleep(2000); System.out.println("当前的线程名字:"+Thread.currentThread().getName()); } catch (InterruptedException e) { System.out.println("当前线程"+Thread.currentThread().getName()+"中断异常"); } } }); } } //关闭线程池 fixedThreadPool.shutdown(); } }
1.2.newSingleThreadExecutor 单线程化的线程池 例子
创建一个单线程化的线程池 它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
package com.Li.xcchi02; /** * @Description: 通过实现Runnable接口实现多线程 * @auther:Li Ya Hui * @Time:2021年4月22日下午2:15:32 */ public class MyThread implements Runnable { @Override public void run() { try { Thread.sleep(1000); System.out.println("当前线程的名字:"+Thread.currentThread().getName()); //模拟异常 System.out.println(2/0); //中断异常,看是否会补一个线程 } catch (InterruptedException e) { System.err.println("此线程中断:"+Thread.currentThread().getName()); } } } package com.Li.xcchi02; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Description: 测试类 测试线程池SingleThreadExecutor * @Description: 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。 * 如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行 * 顺序按照任务的提交顺序执行 * @auther:Li Ya Hui * @Time:2021年4月22日下午2:23:14 */ public class Test { public static void main(String[] args) { //利用Executors 创建 SingleThreadExecutor 线程池 ExecutorService singlepool = Executors.newSingleThreadExecutor(); //创建五个线程 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); //将任务放到线程池中 singlepool.execute(t1); singlepool.execute(t2); singlepool.execute(t3); //关闭线程池 singlepool.shutdown(); } }
- 单线程小结
- 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。
如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行
顺序按照任务的提交顺序执行
1.3.newCachedThreadPool 可缓存线程池 例子
创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程 当执行第二个任务时且第一个已经完成,会重复使用执行第一个任务的线程,而不用每次新建线程
package com.Li.CachedThreadPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Description: 创建 CachedThreadPool 多线程 用来实现缓存多线程 * @auther:Li Ya Hui * @Time:2021年4月22日下午3:05:43 */ public class Test { public static void main(String[] args) throws InterruptedException { //创建一个CatchedThreadPool 可缓存的线程池 ExecutorService cached = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { if (!cached.isShutdown()) { Thread.sleep(1000); cached.execute(new Runnable() { @Override public void run() { System.out.println("当前线程的名字为:"+Thread.currentThread().getName()); } }); }; } //关闭线程池 cached.shutdown(); } }
通过使用线程睡眠胡不使用线程睡眠我们发现当执行第二个任务时且第一个已经完成,会重复使用执行第一个任务的线程,而不用每次新建线程
1.4.定时器的讲解
Timer & TimerTask的讲解
Timer用来执行任务的类,所以称为定时器
Timer Task:每次具体要做什么内容,所以称之为定时任务类
搭配代码案例
package com.Li.TimerTasks; import java.util.TimerTask; /** * @Description: 定时任务类 * @auther:Li Ya Hui * @Time:2021年4月22日下午3:38:56 */ public class MyTimerTask extends TimerTask { @Override public void run() { System.out.println("我设定的定时任务就是在控制台输出:你好。。。。。"); } } package com.Li.TimerTasks; import java.util.Timer; import java.util.TimerTask; /** * @Description: 测试类 测试JDK中的定时器 定时任务类 * @auther:Li Ya Hui * @Time:2021年4月22日下午3:40:23 */ public class Test { public static void main(String[] args) throws InterruptedException { //现在需要一个定时器类 Timer timer = new Timer(); //我的定时器任务类 TimerTask time = new MyTimerTask(); //定时调度 任务 起始时间 间隔时间 timer.schedule(time,0 , 2000); //线程睡眠 Thread.sleep(4000); //取消定时器 timer.cancel(); } }
总结:
Timer用来执行任务的类,所以称为定时器
Timer Task:每次具体要做什么内容,所以称之为定时任务类
1.5.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 例子
package com.Li.ScheduledThreadPool; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * @Description: ScheduledThreadPool 创建一个定长线程池 , 支持定时及周期性任务执行 * @auther:Li Ya Hui * @Time:2021年4月22日下午4:41:14 */ public class Test { public static void main(String[] args) throws InterruptedException { //创建一个定长线程池 ScheduledExecutorService sched = Executors.newScheduledThreadPool(5); //参数的释义 线程任务 、 延迟时间 、 间隔时间 、 时间单位 sched.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("当前线程的名字:"+Thread.currentThread().getName()); } }, 1, 2, TimeUnit.SECONDS);// 内部 Runnable类 延迟1s 每次间隔2s 时间单位秒 //主线程休眠5秒 Thread.sleep(5000); //关闭多线程 sched.shutdown(); } }
1.5.2 scheduleAtFixedRate()参数解析
- 第一个参数是你要提交的任务
- 第二个参数是你初始化后多少秒开始执行第一个任务(只在初始化有用)
- 第三个参数是 period,也就是周期,单位是long,你设置多少就是每隔多少时间
- 第四个参数是时间单位,为前面第二、三个参数的时间单位,我这里的是秒
多线程总结概要
- 线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外的开销,提高了响应速度。
多线程体系结构
(1)Executor,线程池顶级接口;
(2)ExecutorService,线程池次级接口,对Executor做了一些扩展,增加一些功能;
(3)ScheduledExecutorService,对ExecutorService做了一些扩展,增加一些定时任务相关的功能;
(4)AbstractExecutorService,抽象类,运用模板方法 设计模式实现了一部分方法;
(5)ThreadPoolExecutor,普通线程池类,这也是我们通常所说的线程池,包含最基本的一些线程池操作相关的方法实现;
(6)ScheduledThreadPoolExecutor,定时任务线程池类,用于实现定时任务相关功能;
(7)ForkJoinPool,新型线程池类,java7中新增的线程池类,基于工作窃取理论实现,运用于大任务拆小任务、任务无限多的场景;
(8)Executors,线程池工具类,定义了一些快速实现线程池的方法(谨慎使用);