线程池概念
线程池可以看做是一个池子,在这个池子中存储了很多线程,线程池也可以说是一个复用线程的技术。
线程池存在的意义
系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理时对系统资源的消耗。针对这一种情况,为了提高性能,我们就可以采用线程池。线程池在启动的时,会创建大量空闲线程,当我们向线程池提交任务的时,线程池就会启动一个线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次返回到线程池中称为空闲状态。等待下一次任务的执行。
线程池的核心原理
- 创建一个池子,池子中的空的
- 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还池子,下次在提交任务时,不需要创建新的线程,直接复用已有的线程即可
- 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
使用线程池的步骤
- 创建线程池
- 提交任务
- 所有任务执行完毕,关闭线程池
Executors
Executors:线程池的工具类通过调用静态方法来创建线程池
代码实现:
package com.liming.mythreadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPoolDemo01 {
public static void main(String[] args) {
//1,获取线程池对象
ExecutorService pool = Executors.newCachedThreadPool();
ExecutorService pool1 = Executors.newFixedThreadPool(3);
//2,提交任务
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//3,销毁线程(不建议关闭)
pool.shutdown();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "---"+i);
}
}
}
运行上述程序我们可以发现,第一种方式线程池里面有5个线程,第二种线程池中只有固定的3个线程
自定义线程池
上述Java工具类获取的线程池很方便但是不够灵活,当我们提交的任务比较多那么任务就会排队等待,所以我们就要自己定义线程池来修改队伍的长度。
创建自定义线程池方法:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
代码实现:
参数详解:
我们可以把自定义线程池理解成一个餐厅,假如餐厅最多有6名服务员,3名正式工,3名零时工。
任务拒绝策略:
RejectedExecutionHandler是jdk提供的一个任务拒绝策略接口,它下面存在4个子类。
不断的提交事务,会有以下三个临界点:
- 当核心线程满时,在提交任务就会排队
- 当核心线程满,队列满时,会创建临时线程
- 当核心线程满,队列满,临时线程满是,会触发任务拒绝策略