Java线程池(万字图文详解)

Java线程池(万字图文详解)-mikechen

Java线程池在Java面试经常被问到,比如:Java线程池作用,以及Java线程池的原理和使用等,下面我一一来详解@mikechen

Java线程池定义

Java线程池,全称是Java Thread Pool,是一种池化技术,主要通过池化思想管理线程的工具,用于管理和调度线程。

 

Java线程池作用

Java线程池的作用,主要包含如下4点:

1.提高性能

线程池可以重复利用已创建的线程,避免了频繁创建和销毁线程的开销。

2.提高可管理性

通过限制线程的数量和队列的大小,可以更好地管理系统资源。

3.提高响应能力

由于线程已经准备好,可以更快地响应任务请求,如果每次任务请求都需要创建一个新的线程,那么响应时间将会比使用线程池更长。

4.更好的任务调度

线程池可以通过任务队列来调度任务的执行顺序,避免任务之间的互相干扰和相互等待。

 

Java线程池创建

Java线程池创建,如要包含如下几种:

Java线程池(万字图文详解)-mikechen

1.创建一个固定大小的线程池

如下所示:

ExecutorService executor = Executors.newFixedThreadPool(5);

这种方式会创建一个固定大小的线程池,这种线程池适合任务量比较稳定的场景。

 

2.创建一个只有一个线程的线程池

如下所示:

ExecutorService executor = Executors.newSingleThreadExecutor();

该线程池只有一个线程,这种线程池适合需要顺序执行任务,保证任务按照一定顺序执行的场景。

 

3.创建⼀个可缓存的线程池

如下所示:

ExecutorService executor = Executors.newCachedThreadPool();

创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,这种线程池适合短时间内需要大量线程的场景。

 

4.创建定时周期固定的线程池

如下所示:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
executor.schedule(new MyTask(1), 5, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(new MyTask(2), 1, 5, TimeUnit.SECONDS);
executor.shutdown();

这个线程池就是为了定时而发明的,它支持定时或周期性执行任务,比如:10秒钟执行一次任务。

 

5.创建定时或周期性任务的单个线程池

如下所示:

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(new MyTask(1), 5, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(new MyTask(2), 1, 5, TimeUnit.SECONDS);
executor.shutdown();

创建一个只有一个线程的线程池,可以用来执行定时或周期性任务。

 

6.创建工作窃取线程池

如下所示:

ExecutorService executor = Executors.newWorkStealingPool();
for (int i = 0; i < 10; i++) {
    executor.execute(new MyTask(i));
}
executor.shutdown();

创建一个工作窃取线程池,当一个线程执行完自己的任务队列中的任务后,就会从其他线程的任务队列中窃取任务来执行,适合使用在很耗时的操作。

 

7.最原始的创建线程池的⽅式

可以通过ThreadPoolExecutor 手动创建线程池,这也是阿里等大厂推荐使用方式。

 

Java线程池参数

如下所示:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
  this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
    Executors.defaultThreadFactory(), defaultHandler);
}

以下是Java自定义线程池的7大参数说明:

Java线程池(万字图文详解)-mikechen

 

Java线程池使用

下面是一个简单的Java线程池创建示例:

// 创建一个线程池,包括5个核心线程和10个最大线程,线程存活时间为1分钟,使用默认的任务队列和拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());

// 提交任务
executor.execute(new Runnable() {
    public void run() {
        // 任务执行的代码
    }
});

// 关闭线程池
executor.shutdown();

在创建线程池时,需要根据实际需求灵活配置线程池的大小、任务队列类型和线程的创建方式等参数,以达到最佳的性能和效果。

 

Java线程池原理

线程池的工作原理,如下图所示:

Java线程池(万字图文详解)-mikechen

线程池的工作流程,主要分为如下5步:

1.检查线程池是否已满

当一个任务需要执行时,线程池会检查线程池中是否有空闲的线程可用,如果有,那么一个空闲的线程会被分配给该任务执行。

2.将任务放入队列

如果线程池中没有空闲的线程可用,那么任务会被放到任务队列中等待执行,直到有空闲的线程可用。

3.准备开始处理任务

当一个线程完成了任务的执行后,它会返回线程池,并且准备处理下一个任务。

4.如果已满执行拒绝策略

如果线程池中的线程数量已经达到了限制,而且任务队列已经满了,那么线程池会拒绝该任务并执行拒绝策略。

常见的拒绝策略有以下4种,如下图所示:

Java线程池(万字图文详解)-mikechen

更加想的拒绝策略,请查看:Java线程池拒绝策略详解(4种常见拒绝策略)

5.释放线程池资源

当应用程序关闭时,线程池会关闭所有的工作线程,并释放相关的资源。

 

Java线程池应用

具体来说,在以下几种情况下建议使用Java线程池:

  1. 处理IO密集型任务,例如读写文件、网络传输等。
  2. 处理CPU密集型任务,例如加密解密、图像处理等。
  3. 需要处理大量任务的并发环境,例如Web服务器、消息队列等。
  4. 需要对任务进行优先级排序或按照一定规则进行调度的情况。

以上就是Java线程池的详解,希望对你掌握Java线程池有所帮助!

作者简介

陈睿|mikechen,10年+大厂架构经验,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

关注作者「mikechen」公众号,获取更多技术干货!

评论交流
    说说你的看法