文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JAVA基础:线程池的使用

2023-09-08 22:19

关注

目录

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)当需要执行一个任务时,线程池会从工作队列中获取一个任务。

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

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

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

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

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

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

     public ThreadPoolExecutor(int corePoolSize,  int maximumPoolSize,  long keepAliveTime,  TimeUnit unit,  BlockingQueue workQueue,  ThreadFactory threadFactory,  RejectedExecutionHandler handler) {    }
参数说明
corePoolSize核心线程数量,线程池维护线程的最少数量
maximumPoolSize线程池维护线程的最大数量
keepAliveTime非核心线程的最长空闲时间,超过该时间的空闲线程会被销毁
unitkeepAliveTime的单位,有NANOSECONDS(纳秒)、MICROSECONDS(微秒)、MILLISECONDS(毫秒)、SECONDS(秒)
workQueue任务缓冲队列(阻塞队列)
threadFactory线程工厂,用于创建线程,一般用默认的即可
handler线程池对拒绝任务的拒绝策略

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

ThreadPoolExecutor的执行流程如下:

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

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

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

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

 ThreadPoolExecutor提供了四种拒绝策略:

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

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

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

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

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

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

  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 参数说明

b. 线程池执⾏流程

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

4.1.拥有适当数量的线程

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

4.2.使用合适的工作队列

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

4.3.处理异常

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

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

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

5.1.引入jar包

    concurrent    concurrent    1.3.4      com.google.guava     guava     23.0

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;@Componentpublic 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);                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;@Component@EnableAsyncpublic 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();        }    }}

运行

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

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

[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

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

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

[8] https://blog.csdn.net/weixin_37686415/article/details/112549576

来源地址:https://blog.csdn.net/qq_20957669/article/details/131212742

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯