JAVA基础:线程池的使用

这篇具有很好参考价值的文章主要介绍了JAVA基础:线程池的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1.概述

2.线程池的优势​​​​​​​

2.1.线程池为什么使用自定义方式?

2.2.封装的线程池工具类有什么好处?

3.线程池的七大参数

3.线程池的创建

3.1. 固定数量的线程池

3.2. 带缓存的线程池

3.3. 执⾏定时任务

3.4. 定时任务单线程

3.5. 单线程线程池

3.6. 根据当前CPU⽣成线程池

3.7. ThreadPoolExecutor★★★

4.使用线程池的最佳实践

4.1.拥有适当数量的线程

4.2.使用合适的工作队列

4.3.处理异常

4.4.使用线程池内置的监控和调试工具

5.线程池的使用案例

5.1.引入jar包

5.2.初始化线程池

5.3.测试案例

5.结论

6.鸣谢


1.概述

线程池是一种常见的多线程编程技术,它允许我们在系统中使用一个固定数量的线程来执行任务,以免过多的线程拉低了系统的性能。在本文中,我们将探讨线程池的使用和一些最佳实践,以便在您的代码中获得更好的性能和可维护性。

线程池是一种用于管理和调度多个线程的技术。线程池主要由三个部分组成:

  • 线程管理器:负责启动、停止和管理线程池中的线程。
  • 工作队列:用于存储要执行的任务。
  • 线程池:包含线程管理器和工作队列。

线程池的工作原理如下:

1)当需要执行一个任务时,线程池会从工作队列中获取一个任务。

2)线程管理器会从线程池中获取一个可用的线程来执行任务。

3)任务执行完成后,线程会返回到线程池中,等待下一个任务的分配。

2.线程池的优势​​​​​​​

2.1.线程池为什么使用自定义方式?

因为 java 自带线程池都会有可能造成内存不足的问题。自定义线程池,根据服务器配置定制线程池核心线程、最大线程等,是最好的方式。

2.2.封装的线程池工具类有什么好处?

  • 扩展性高
  • 可注解形式实现执行
  • 可根据业务需要注册不同的线程池,区分业务模块使用
  • 可以执行无返回值线程任务,可以执行有返回值的线程任务

3.线程池的七大参数

核心线程数、最大线程数、多余线程存活时间、时间单位、线程工厂、阻塞队列、拒绝策略

 /**
     * @param corePoolSize 核心线程数 -> 线程池中保持的线程数量,即使它们是空闲的也不会销毁,
     *        除非设置了{@code allowCoreThreadTimeOut}核心线程超时时间
     * @param maximumPoolSize 最大线程数 -> 线程池中允许接收的最大线程数量
     *        如果设定的数量比系统支持的线程数还要大时,会抛出OOM(OutOfMemoryError)异常
     * @param keepAliveTime 最大存活时间 -> 当前线程数大于核心线程数的时候,
     *        其他多余的线程接收新任务之前的最大等待时间,超过时间没有新任务就会销毁.
     * @param unit {@code keepAliveTime}最大存活时间的单位.eg:TimeUnit.SECONDS
     * @param workQueue 工作队列 -> 保存任务直到任务被提交到线程池的线程中执行.
     * @param threadFactory 线程工厂 -> 当线程池需要创建线程得时候会从线程工厂获取新的实例.
     *        (自定义ThreadFactory可以跟踪线程池究竟何时创建了多少线程,也可以自定义线程的名称、
     *        组以及优先级等信息,甚至可以任性的将线程设置为守护线程.
     *        总之,自定义ThreadFactory可以更加自由的设置线程池中所有线程的状态。)
     * @param handler 当线程数量等于最大线程数并且工作队列已满的时候,再有新的任务添加进来就会进入这个handler,
     *        可以理解为设置拒绝策略(此处不清楚的可以看一下ThreadPoolExecutor中的execute方法的注释)
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    }
参数 说明
corePoolSize 核心线程数量,线程池维护线程的最少数量
maximumPoolSize 线程池维护线程的最大数量
keepAliveTime 非核心线程的最长空闲时间,超过该时间的空闲线程会被销毁
unit keepAliveTime的单位,有NANOSECONDS(纳秒)、MICROSECONDS(微秒)、MILLISECONDS(毫秒)、SECONDS(秒)
workQueue 任务缓冲队列(阻塞队列)
threadFactory 线程工厂,用于创建线程,一般用默认的即可
handler 线程池对拒绝任务的拒绝策略

示例:创建一个核心线程数为5,最大线程数为10,任务队列容量为100的线程池

java线程池使用,JAVA SE,java,jvm,开发语言,多线程,线程池

ThreadPoolExecutor的执行流程如下:

1、当线程池中新加入一个任务时,先判断核心线程数是否达到最大值,如果为false则创建一个核心线程执行任务,如果为true执行第二步;

2、判断当前任务队列是否已满,如果为false,则将任务加入到队列中等待执行;如果为true,则判断当前线程数是否达到最大线程数;

3、如果当前线程数没有达到最大线程数,则创建临时线程来执行任务,如果达到最大线程数,则执行拒绝策略。

java线程池使用,JAVA SE,java,jvm,开发语言,多线程,线程池

拒绝策略指的是线程池中线程数量达到最大值,任务队列为满时,来了新任务的处理方式

 ThreadPoolExecutor提供了四种拒绝策略:

AbortPolicy:丢弃任务并抛出RejectedExecutionException异常(默认)

CallerRunsPolicy:由调用线程处理该任务( 常用)

DiscardPolicy:丢弃任务,但是不抛出异常。

DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。

当然也可以自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可

3.线程池的创建

线程池使用规范(阿里巴巴)

  1. 创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
  2. 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 自行创建线程,有可能造成系统创建大量同类线程而导致消耗完内存或者 “过度切换”的问题。
  3. 线程池不允许使用 Executors工厂类去创建(阿里的Java规范不推荐使用类Executors的静态方法创建线程池),而是通过new ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

线程池的创建⽅法总共有 7 种,但总体来说可分为 2 类:

        1. 通过 ThreadPoolExecutor 创建的线程池;

        2. 通过 Executors 创建的线程池。

线程池的创建⽅式总共包含以下 7 种

(其中 6 种是通过 Executors 创建的, 1 种是通过ThreadPoolExecutor 创建)

        1. Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待;

        2. Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;

        3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;

        4. Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;

        5. Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池;

        6. Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】。

        7. ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置,后⾯会详细讲。

3.1. 固定数量的线程池

线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客

3.2. 带缓存的线程池

​​​​​​线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客

3.3. 执⾏定时任务

线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客

3.4. 定时任务单线程

线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客

3.5. 单线程线程池

线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客

为什么不直接用线程?单线程的线程池又什么意义?

        1. 复用线程。

        2. 单线程的线程池提供了任务队列和拒绝策略(当任务队列满了之后(Integer.MAX_VALUE),新来的任务就会拒绝策略)

3.6. 根据当前CPU⽣成线程池

线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客

3.7. ThreadPoolExecutor★★★

线程池的使用(7种创建方法)

a. ThreadPoolExecutor 参数说明

java线程池使用,JAVA SE,java,jvm,开发语言,多线程,线程池

b. 线程池执⾏流程

java线程池使用,JAVA SE,java,jvm,开发语言,多线程,线程池

4.使用线程池的最佳实践

以下是使用线程池的一些最佳实践:

4.1.拥有适当数量的线程

线程池中的线程数量应该根据应用程序的需求来确定。通常情况下,线程池中的线程数量应该等于处理器数量加一。

4.2.使用合适的工作队列

线程池中的工作队列应该根据应用程序的需求来选择。如果需要执行大量的任务并且希望通过控制队列大小来限制系统的负载,则应该使用有界队列。如果希望系统能够保持高吞吐量并且不想限制队列大小,则应该使用无界队列

4.3.处理异常

线程池中的任务可能会抛出异常,因此我们应该在代码中处理这些异常。当任务抛出异常时,可以将异常记录到日志文件中或者通过线程池的回调函数进行处理。

4.4.使用线程池内置的监控和调试工具

许多线程池都提供了监控和调试工具,这些工具可以帮助我们诊断线程池中的问题。例如,线程池可以提供有关线程数量、队列大小和任务执行速度的统计信息。

5.线程池的使用案例

5.1.引入jar包

<!-- https://mvnrepository.com/artifact/concurrent/concurrent -->
<dependency>
    <groupId>concurrent</groupId>
    <artifactId>concurrent</artifactId>
    <version>1.3.4</version>
</dependency>
 <dependency>
     <groupId>com.google.guava</groupId>
     <artifactId>guava</artifactId>
     <version>23.0</version>
</dependency>

5.2.初始化线程池


import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @ClassName: AsyncScheduledTaskConfig
 * @author: dyt
 * @since: 2023/06/16 下午 4:58
 */
@Component
public class AsyncScheduledTaskConfig {

    @Bean
    public Executor myAsync() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //最大线程数
        executor.setMaxPoolSize(100);
        //核心线程数
        executor.setCorePoolSize(10);
        //任务队列的大小
        executor.setQueueCapacity(10);
        //线程前缀名
        executor.setThreadNamePrefix("dyt-thread-");
        //线程存活时间
        executor.setKeepAliveSeconds(30);

        /**
         * 拒绝处理策略
         * CallerRunsPolicy():交由调用方线程运行,比如 main 线程。
         * AbortPolicy():直接抛出异常。
         * DiscardPolicy():直接丢弃。
         * DiscardOldestPolicy():丢弃队列中最老的任务。
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //线程初始化
        executor.initialize();
        return executor;
    }
}

5.3.测试案例


import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName: ScheduleTask
 * @author: dyt
 * @since: 2023/06/19 下午 3:59
 */
@Component
@EnableAsync
public class ScheduleTask {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Async("myAsync")
    @Scheduled(fixedRate = 2000)
    public void testScheduleTask() {
        try{
            Thread.sleep(6000);
            System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

运行

java线程池使用,JAVA SE,java,jvm,开发语言,多线程,线程池

补充:
使用@Bean(“beanName”)定义线程池
然后在@Async(“beanName”)中引用指定的线程池 

5.结论

线程池是一种重要的多线程编程技术,可以帮助我们提高代码的性能和可维护性。通过了解线程池的最佳实践和使用经验,我们可以更好地使用线程池来构建高效的、稳定的多线程应用程序。

6.鸣谢

[1] https://blog.csdn.net/m0_48273471/article/details/124145012

[2] https://blog.csdn.net/YQQAGH178/article/details/119828128

[3] https://blog.csdn.net/qq_43681755/article/details/111057195

[4] https://blog.csdn.net/weixin_48410604/article/details/119386267

[5] https://blog.csdn.net/qq_42889280/article/details/123995250#t0

[6] https://blog.csdn.net/qq_24983911/article/details/94722569

[7] https://blog.csdn.net/qq_42889280/article/details/123995250#t0

[8] https://blog.csdn.net/weixin_37686415/article/details/112549576文章来源地址https://www.toymoban.com/news/detail-677788.html

到了这里,关于JAVA基础:线程池的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java线程池的入门

    一、线程池的优势 1.降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗。 2.提高系统相应速度,当有任务到达时,通过复用已存在的行程,无需等待新线程的创建便能立刻执行。 3.方便线程并发数的管控,因为线程若是无限制创建,可能会导致内存

    2024年02月08日
    浏览(39)
  • Java多线程之线程池的参数和配置

    在Java多线程编程中,线程池是一种常见的技术,用于管理线程的创建和销毁。线程池中的线程可以被重复利用,从而减少了线程的创建和销毁的开销,提高了程序的性能。在Java中,线程池的参数和配置非常重要,不同的参数和配置会影响线程池的性能和行为。 Java线程池的主

    2024年02月16日
    浏览(35)
  • Java 线程池的原理与实现

    最近在学习线程池、内存控制等关于提高程序运行性能方面的编程技术,线程池就是其中之一,一提到线程,我们会想到以前《操作系统》的生产者与消费者,信号量,同步控制等等。 一提到池,我们会想到数据库连接池,但是线程池又如何呢? 建议 :在阅读本文前,先理

    2024年02月13日
    浏览(33)
  • Java 线程池的基本操作

    2024年02月20日
    浏览(33)
  • SpringBoot线程池和Java线程池的实现原理

    @ 目录 使用默认的线程池 方式一:通过 @Async 注解调用 方式二:直接注入 ThreadPoolTaskExecutor 线程池默认配置信息 SpringBoot 线程池的实现原理 覆盖默认的线程池 管理多个线程池 JAVA常用的四种线程池 newCachedThreadPool newFixedThreadPool newScheduledThreadPool newSingleThreadExecutor Java 线程池中

    2023年04月11日
    浏览(43)
  • 你知道 Java 线程池的原理吗?

    Java线程池是用于管理和复用线程的机制,它可以帮助开发者有效地管理线程的生命周期和资源,并提高应用程序的性能和稳定性。 1. 线程池概述 在计算机科学中,线程池是一种可用来执行异步任务的线程队列。它主要包含以下几个组成部分: 工作队列(BlockingQueue) :用于

    2024年04月12日
    浏览(41)
  • java 线程池的理解与运用,实例支撑

    线程池的定义和特点 线程池是一种多线程处理形式,它可以在程序启动时创建一定数量的线程,并将它们保存在一个线程池中,然后在需要执行任务时,从线程池中取出一个线程来执行任务,任务执行完毕后,线程并不会销毁,而是放回线程池中等待下一次任务的执行。 线

    2024年02月07日
    浏览(33)
  • Java多线程 - 创建线程池的方法 - ThreadPoolExecutor和Executors

    线程池介绍 什么是线程池 ? 线程池就是一个可以复用线程的技术。 不使用线程池的问题 : 如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。 线程池工作原理 : 例如线程池

    2023年04月16日
    浏览(44)
  • SpringBoot线程池和Java线程池的用法和实现原理

    @ 目录 使用默认的线程池 方式一:通过 @Async 注解调用 方式二:直接注入 ThreadPoolTaskExecutor 线程池默认配置信息 SpringBoot 线程池的实现原理 覆盖默认的线程池 管理多个线程池 JAVA常用的四种线程池 newCachedThreadPool newFixedThreadPool newScheduledThreadPool newSingleThreadExecutor Java 线程池中

    2023年04月11日
    浏览(35)
  • 从源码全面解析Java 线程池的来龙去脉

    👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主 📕系列专栏:Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码系列 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦 🍂博主正在努

    2024年02月03日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包