Java使用线程池
线程池类位于 java.util.concurrent 包
-
简介
Java虽然支持多线程,启动一个新的线程非常简单。但是频繁创建销毁线程需要消耗大量的系统资源(线程资源、栈空间等),更好的做法是使用【线程池】。
![线程池]()
-
Java标准库提供ExecutorService接口表示线程池,它的典型用法如下:
- submit(Runnable runnable)接收实现 Runnable 接口的对象。
// 创建固定大小的线程池: ExecutorService executor = Executors.newFixedThreadPool(3); // 提交任务: executor.submit(task1); executor.submit(task2); executor.submit(task3); executor.submit(task4); executor.submit(task5); -
常见的 ExecutorService 接口实现类:
- FixedThreadPool:线程数固定的线程池。
- CacheThreadPool:线程数根据任务动态调整线程池,无上限。
- SingleThreadExecutor:仅单线程执行的线程池。
- ScheduleThreadPool:定时任务、循环执行。
(创建这些线程池的方法都被封装到
Executors这个类中)ExecutorService es = Executors.newFixedThreadPool(4); -
3种线程池关闭方式:
- .shutdown():等待正在执行的任务先完成,然后再关闭。
- .shutdownNow():立刻停止正在执行的任务(强制关闭)。
- .awaitTermination():等待指定的时间后让线程池关闭。
-
【必要性说明】:线程池最后需要手动关闭。
import java.util.concurrent.*; public class Main { public static void main(String[] args) { ExecutorService es = Executors.newFixedThreadPool(4); for (int i = 0; i < 6; i++) { es.submit(new Task()); } // 关闭线程池: es.shutdown(); } } class Task implements Runnable { @Override public void run() { System.out.println("a"); } } -
创建动态线程池
-
原理:基于 CacheThreadPool 底层源码,创建存在 min 与 max 的线程池。
- 线程数量:0 ~ 无限大。
- 每个线程的最长存活时间:60秒。
- 工作队列为:SynchronousQueue<Runnable>。
![image-20220822162648332]()
// 创建指定 min 与 max 的线程池 int min = 4; int max = 10; ExecutorService es = new ThreadPoolExecutor(min, max,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
-
-
【小总结】
- 线程池的使用使得不再需要通过以往的.start()方式启动线程,而是直接将线程置于线程池中即可。
- CacheThreadPool有存活时间,FixedThreadPool与SingleThreadExecutor没有存活时间(超时时间)。
-
ScheduleThreadPool【定时任务】
-
简介:特殊的线程池,定时任务、可以反复执行。
-
执行类型:
- FixedRate:任务总是以固定的时间触发,而不管任务执行时间多长。
- FixedDelay:上一次任务执行完毕后等待固定的时间间隔,再执行下一次任务。
![在这里插入图片描述]()
ScheduledExecutorService s=Executors.newScheduledThreadPool(4);// 1秒后执行任务,而且只执行一次。 ses.schedule(new Task("one-time"), 1, TimeUnit.SECONDS);// FixedRate,10秒后开始执行定时任务,每3秒执行。 ses.scheduleWithFixedRate(new Task(),10,3, TimeUnit.SECONDS); // FixedDelay,10秒后开始执行定时任务,每3秒执行。 ses.scheduleWithFixedDelay(new Task(),10,3, TimeUnit.SECONDS);// lambda表达式 ses.schedule(()->{ System.out.PrintLn("hello"); }, 1, TimeUnit.SECONDS); -
-
思考以下问题:
- 在FixedRate模式下,假设每秒触发,而某次任务的执行时间超过了1s,那么会不会造成并发执行?如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会并发执行。
- 如果任务抛出了异常,那么后续任务会不会继续执行 ?如果任务发生异常,将禁止后续任务执行。
-
【Timer】说明:
Java标准库中海提供了一个java.util.Timer类,这个类也可以执行定时任务,但这个类所代表的是一个旧的体系,并不推荐,Shedule 完全可以代替 Timer。




浙公网安备 33010602011771号