作者
:学Java的冬瓜
博客主页
:☀冬瓜的主页
专栏
:【JavaEE】
分享
:纵是百万大军,又如何!——李大帅《画江湖之不良人》
主要内容
:什么是线程池,线程池的应用,用普通方法替代构造方法实现工厂模式。线程池标准库的使用,变量捕获,关于线程池的源码分析,ThreadPoolExecutor的构造方法参数分析,线程池拒绝策略。自定义实现线程池。
我们知道,线程池、数据库连接池、字符串常量池等是一种类型的,就是用一个容器,把同类型的东西装进这个容器,便于后面使用,所以叫做"池"。
那么我们为什么要使用线程池?当线程数量足够多时,我们发现线程申请资源和释放资源的花费时间也会达到一个高度,使我们的程序效率变低,此时有两种方法:1、搞一个比线程更轻量的线程,协程/纤程,go中就有纤程,所以go对并发编程有着优势;2、可以使用线程池,在创建线程池的时候一次创建多个线程对象,待使用线程时,从线程池中取出线程执行任务。
那么为什么使用线程池要快呢?因为如果不使用线程池,线程对象在应用程序中实例化,并通过操作系统提供的api创建和管理线程(包括销毁);而使用线程池后,线程池中的线程对象不是由操作系统创建的,而是由线程池管理程序在程序运行时动态创建。我们知道应用程序的执行要比操作系统执行快很多。因此当我们需要使用多个线程来执行任务时,线程池就可以很大的提高效率。
Executors
的静态方法来创建对象(这里的对象是线程池)。再用ExecutorService
接收(后面会分析为什么)。工厂类
工厂方法
,这里就使用了工厂模式
这种设计模式。使用普通方法,来代替构造方法,创建对象。
public class Point{
// 笛卡尔坐标系构造方法
public Point(double x, double y) {}
// 极坐标系构造方法
public Point(double r, double a) {}
}
pool.submit()
方法来使用线程池执行任务。public class Main {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
int n = i;
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println(n);
}
});
}
}
}
Executor
这个工厂类的工厂方法中的返回值都是ThreadPoolExecutor
类型的,只是传入的参数不同,所以最终实现的线程池不一样。ThreadPoolExecutor
继承了AbstractExecutorService
这个抽象类,而AbstractExecutorService
抽象类实现了ExecutorService
接口。因此相当于ThreadPoolExecutor类实现了ExecutorService接口,因此可以使用ExecutorService接收线程池对象。1.corePoolSize:
核心线程数2.maximumPoolSize:
总线程数(正式员工和零时工之和就是总线程数)3.keepAliveTime和unit:
二者一起描述零时工(空闲线程)最大摸鱼时间,keepAliveTime是空闲线程等待工作的最大时间,unit是时间的单位。4.BlockingQueue workQueue
是使用阻塞队列,因为如果当前没有任务需要执行,那线程池中的线程应当陷入阻塞;或者任务满了,那任务入队会先阻塞。5.threadFactory:
用于创建线程。import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
// 自定义线程池
class MyThreadPool{
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// 构造方法,创建线程,且取出任务队列中的任务,在进行执行。
public MyThreadPool(int n){
for (int i = 0; i < n; i++) {
Thread t = new Thread(()->{
while (true){
try {
Runnable task = queue.take();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
// 向任务队列添加任务
public void submit(Runnable runnable) throws InterruptedException {
queue.put(runnable);
}
}
// Main测试类
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThreadPool pool = new MyThreadPool(10);
for (int j = 0; j < 100; j++) {
int n = j;
pool.submit(new Runnable() { // runnable描述每个任务
@Override
public void run() {
System.out.println(n);
}
});
}
}
}