当前位置: 首页 > news >正文

为什么要用线程池?

线程池是一种管理和复用线程资源的机制,它由一个线程池管理器和一组工作线程组成。线程池管理器负责创建和销毁线程池,以及管理线程池中的工作线程。工作线程则负责执行具体的任务。

线程池的主要作用是管理和复用线程资源,避免了线程的频繁创建和销毁所带来的开销。
线程池包含两个重要的组成部分:

  1. 线程池大小:指线程池中所能容纳的最大线程数。线程池大小一般根据系统的负载情况和硬件资源来设置。

  2. 工作队列:用于存放等待执行的任务。当线程池中的工作线程已经全部被占用时,新的任务将被加入到工作队列中等待执行。

线程池创建方式

Java中线程池的创建方式主要有以下几种:

  1. 使用 ThreadPoolExecutor 类手动创建:通过 ThreadPoolExecutor 类的构造函数自定义线程池的参数,包括核心线程数、最大线程数、线程存活时间、任务队列等。

  2. 使用 Executors 类提供的工厂方法创建:通过 Executors 类提供的一些静态工厂方法创建线程池,例如 newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool 等。

  3. 使用 Spring 框架提供的 ThreadPoolTaskExecutor 类:在 Spring 框架中可以通过 ThreadPoolTaskExecutor 类来创建线程池。

不同的创建方式适用于不同的场景,通常可以根据实际情况选择合适的方式创建线程池。手动创建 ThreadPoolExecutor 类可以灵活地配置线程池参数,但需要对线程池的各项参数有一定的了解;使用 Executors 工厂方法可以快速创建线程池,但可能无法满足特定的需求,且容易出现内存溢出的情况;而 Spring 框架提供的 ThreadPoolTaskExecutor 类则只能在 Spring 框架中使用。

线程池使用

ThreadPoolExecutor 使用

ThreadPoolExecutor 线程的创建与使用示例如下:

import java.util.concurrent.*;public class ThreadPoolDemo {public static void main(String[] args) {// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // 核心线程数5, // 最大线程数60, // 线程池中线程的空闲时间(单位为秒)TimeUnit.SECONDS, // 时间单位new ArrayBlockingQueue<>(10) // 任务队列);// 提交任务for (int i = 1; i <= 20; i++) {final int taskId = i;executor.submit(() -> {System.out.println("执行任务:" + taskId + ",线程名称:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行时间} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

在上面的示例中,我们通过 ThreadPoolExecutor 类手动创建了一个线程池,设置了线程池的核心线程数为 2,最大线程数为 5,线程空闲时间为 60 秒,任务队列为长度为 10 的 ArrayBlockingQueue。然后我们通过 submit() 方法向线程池中提交了 20 个任务,每个任务会在执行时输出自己的编号和执行线程的名称,然后睡眠1秒钟模拟任务执行时间。最后,我们调用 shutdown() 方法关闭线程池。

Executors 使用

import java.util.concurrent.*;public class ExecutorsDemo {public static void main(String[] args) {// 创建线程池ExecutorService executor = Executors.newFixedThreadPool(5);// 提交任务for (int i = 1; i <= 10; i++) {final int taskId = i;executor.submit(() -> {System.out.println("执行任务:" + taskId + ",线程名称:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行时间} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

在上面的示例中,我们使用了 Executors 工厂类中的 newFixedThreadPool() 方法创建了一个线程池,该线程池有 5 个固定线程。然后我们通过 submit() 方法向线程池中提交了 10 个任务,每个任务会在执行时输出自己的编号和执行线程的名称,然后睡眠 1 秒钟模拟任务执行时间。最后,我们调用 shutdown() 方法关闭线程池。值得注意的是,使用 Executors 工厂类创建线程池虽然非常简单,但是在实际生产环境中并不推荐,因为这种方式很容易导致线程资源被耗尽,从而影响系统的性能和稳定性。

ThreadPoolTaskExecutor 使用

Spring 中 ThreadPoolTaskExecutor 的使用示例如下:

import java.util.concurrent.*;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;public class ThreadPoolTaskExecutorDemo {public static void main(String[] args) {// 创建线程池ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(2); // 核心线程数executor.setMaxPoolSize(5); // 最大线程数executor.setQueueCapacity(10); // 任务队列长度executor.initialize();// 提交任务for (int i = 1; i <= 20; i++) {final int taskId = i;executor.submit(() -> {System.out.println("执行任务:" + taskId + ",线程名称:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行时间} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

在上面的示例中,我们使用了 Spring 框架中的 ThreadPoolTaskExecutor 类创建了一个线程池,设置了线程池的核心线程数为 2,最大线程数为 5,任务队列长度为 10。然后我们通过 submit() 方法向线程池中提交了 20 个任务,每个任务会在执行时输出自己的编号和执行线程的名称,然后睡眠1秒钟模拟任务执行时间。最后,我们调用 shutdown() 方法关闭线程池。注意,在使用 Spring 框架中的 ThreadPoolTaskExecutor 类创建线程池时,我们需要先调用 initialize() 方法进行初始化。

ThreadPoolTaskExecutor 底层还是通过 JDK 中提供的 ThreadPoolExecutor 类实现的。

线程池优点详解

线程池相比于线程来说,它不需要频繁的创建和销毁线程,线程一旦创建之后,默认情况下就会一直保持在线程池中,等到有任务来了,再用这些已有的线程来执行任务,如下图所示:

优点1:复用线程,降低资源消耗

线程在创建时要开辟虚拟机栈、本地方法栈、程序计数器等私有线程的内存空间,而销毁时又要回收这些私有空间资源,如下图所示:


而线程池创建了线程之后就会放在线程池中,因此线程池相比于线程来说,第一个优点就是可以复用线程、减低系统资源的消耗

优点2:提高响应速度

线程池是复用已有线程来执行任务的,而线程是在有任务时才新建的,所以相比于线程来说,线程池能够更快的响应任务和执行任务。

优点3:管控线程数和任务数

线程池提供了更多的管理功能,这里管理功能主要体现在以下两个方面:

  1. 控制最大并发数:线程池可以创建固定的线程数,从而避免了无限创建线程的问题。当线程创建过多时,会导致系统执行变慢,因为 CPU 核数是一定的、能同时处理的任务数也是一定的,而线程过多时就会造成线程恶意争抢和线程频繁切换的问题,从而导致程序执行变慢,所以合适的线程数才是高性能运行的关键。
  2. 控制任务最大数:如果任务无限多,而内存又不足的情况下,就会导致程序执行报错,而线程池可以控制最大任务数,当任务超过一定数量之后,就会采用拒绝策略来处理多出的任务,从而保证了系统可以健康的运行。

优点4:更多增强功能

线程池相比于线程来说提供了更多的功能,比如定时执行和周期执行等功能。

小结

线程池是一种管理和复用线程资源的机制。相比于线程,它具备四个主要优势:1.复用线程,降低了资源消耗;2.提高响应速度;3.提供了管理线程数和任务数的能力;4.更多增强功能。

http://www.lryc.cn/news/91544.html

相关文章:

  • c语言的预处理和编译
  • 网络安全必学 SQL 注入
  • Docker基础知识详解
  • 腾讯、阿里入选首批“双柜台证券”,港股市场迎盛夏升温?
  • CentOS7 使用Docker 安装MySQL
  • 注解和反射复习
  • RocketMQ的demo代码
  • C++ 连接、操作postgreSQL(基于libpq库)
  • Node.js技术简介及其在Web开发中的应用
  • 时间序列分析:原理与MATLAB实现
  • mysql排序之if(isnull(字段名),0,1),字段名 或者 if(isnull(字段名),1,0),字段名
  • 华为OD机试真题 Java 实现【递增字符串】【2023Q1 200分】,附详细解题思路
  • 合并文件解决HiveServer2内存溢出方案
  • 韧性数据安全体系缘起与三个目标 |CEO专栏
  • 华为OD机试真题 Java 实现【火车进站】【牛客练习题】
  • c#快速入门(下)
  • 基于深度学习的目标姿态检测方法_kaic
  • Pycharm设置Python每个文件开头自定义模板(带上声明字符编码、作者名、时间等)
  • Gem相关操作命令
  • 软件测试2023年行情怎么样?仔细讲解!
  • 【1130. 叶值的最小代价生成树】
  • Linux各个目录的全称及含义
  • Cookie和Session原理详解
  • 小程序自动化测试
  • 【linux系统操作】 - 技术一览
  • yield和sleep 区别
  • Redis 注册服务,自动启动
  • 华为OD机试真题 Java 实现【字符统计】【2023 B卷 100分】
  • ASP.NET Core MVC 从入门到精通之自动映射(一)
  • 4. WebGPU 存储缓冲区 (WebGPU Storage Buffers)