一,什么是线程池
线程池是在应用程序启动时创建一定数量的线程,并将它们保存在线程池中。当需要执行任务时,从线程池中获取一个空闲的线程,将任务分配给该线程执行。当任务执行完毕后,线程将返回到线程池,可以被其他任务复用。
二,线程池的运行机制
1. 当任务到达最大时,线程池管理器会检查线程池中是否有空闲的线程。如果有,则将任务分配给空闲线程执行;如果没有,则进入下一步。
2. 如果线程池中的线程数量未达到最大限制,线程池管理器会创建一个新的线程,并将任务分配给该线程执行。
3. 如果线程池中的线程数量已达到最大限制,并且工作队列未满,则将任务放入工作队列中等待执行。
4. 当线程池中的线程执行完任务后,会从工作队列中获取下一个任务并执行。
三,线程池的优点和缺点
线程池的主要优点包括:
1,重用线程:线程池会在内部维护一组可重用的线程,避免了频繁地创建和销毁线程的开销,提高了线程的利用率。
2,控制并发度:线程池可以限制并发执行的线程数量,防止系统过载。通过调整线程池的大小,可以控制并发度,避免资源消耗过大。
3,提供线程管理和监控:线程池提供了一些管理和监控机制,例如线程池的创建、销毁、线程状态的监控等,方便开发人员进行线程的管理和调试。
4,提供任务队列:线程池通常会使用任务队列来存储待执行的任务,这样可以实现任务的缓冲和调度。
四,如何创建线程池
java中其实提供了两种方式:
第一种: 通过工具类完成线程池的创建.[Executors]. 语法简单。但是阿里巴巴不建议使用
第二种: 通过线程池类: ThreadPoolExecutor类. 语法复杂,但是阿里巴巴建议使用。灵活
线程的根接口: Executor. 里面只有一个方法: execute
子接口: ExecutorService。
1.Executors
-
固定大小的线程池对象newFixedThreadPool
-
单一线程池: newSingleThreadExecutor
-
可变线程池: newCachedThreadPool
-
延迟线程池: newScheduledThreadPool
public class Test01 { public static void main(String[] args) { //创建一个固定大小的线程池。返回类型为ExecutorService. // ExecutorService executorService = Executors.newFixedThreadPool(5); //创建单一线程池【池子里面只有一个线程的对象】适合任务顺序执行的。 // ExecutorService executorService = Executors.newSingleThreadExecutor(); //创建可变线程池。【池子中线程的数量会随着任务的大小而变化】 // ExecutorService executorService = Executors.newCachedThreadPool(); //延迟线程池:[指定时间后执行] ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5); //执行线程任务。Runnable Callable. Integer.MAX()整数的最大值。 // for(int i=0;i<10;i++) { //1.必须传递Runnable对象。[1]自己创建一个类实现Runnable接口 [2]匿名内部类对象 [3]lambda表达式: 前提接口必须为函数式接口。 // executorService.execute(new My()); // executorService.execute(new Runnable() { // @Override // public void run() { // System.out.println(Thread.currentThread().getName()+"*************"); // } // }); //表示10秒后执行任务代码块。 // executorService.schedule(()->{ // System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~"); // },10, TimeUnit.SECONDS); executorService.scheduleAtFixedRate(()->{ System.out.println(Thread.currentThread().getName()); },5,2,TimeUnit.SECONDS); // } //关闭线程池 } }
2.ThreadPoolExecutor
public class Test02 {
public static void main(String[] args) {
//核心参数的意思
/**
* int corePoolSize,核心线程数的个数 2
* int maximumPoolSize,最大线程数量 5
* long keepAliveTime, 非核心线程允许空闲的时间
* TimeUnit unit, 时间的单位
* BlockingQueue<Runnable> workQueue 堵塞队列中 3
*/
BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue(5);
ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(2,6,10, TimeUnit.SECONDS,workQueue);
for (int i = 0; i <11; i++) {
poolExecutor.submit(()->{
System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~~");
});
}
}
}
总结:
Executors类中封装好的创建线程池的方法使用方便,但是也有其局限性和风险性,所以我们可以使用 ThreadPoolExecutor 类中的构造方法手动创建线程池的实例, 从而可以根据我们的使用情况来指定参数,满足使用的同时又能规避风险。