线程池ThreadPoolExecutor使用指南

news2024/10/5 21:15:34

在这里插入图片描述

线程池ThreadPoolExecutor使用指南

🧐使用线程池的好处是什么?

统一管理,减少资源获取创建的开销,提高利用率。

🔧线程池的参数

ThreadPoolExecutor​ 3 个最重要的参数:

  • corePoolSize​ : 任务队列未达到队列容量时,最大可以同时运行的线程数量。

  • maximumPoolSize​ : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。

  • workQueue​: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中

ThreadPoolExecutor​其他常见参数 :

  • keepAliveTime​:线程池中的线程数量大于 corePoolSize​ 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime​才会被回收销毁。
  • unit​ : keepAliveTime​ 参数的时间单位。
  • threadFactory​ :executor 创建新线程的时候会用到。
  • handler​ :拒绝策略
🤔你是如何创建线程池的?为什么不建议直接用Executors​创建线程池?

一般不建议直接用Executors​创建线程池的,这种方式缓冲队列没有限制合适的大小(默认整形的最大值),处理不好会有OOM的风险。而是通过 ThreadPoolExecutor​ 构造函数的方式,这样的好处就是更加明确线程池的运行规则,规避资源耗尽的风险。

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }
✨线程池的策略有哪些?

当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时:

常见的策略有拒绝策略:

  • AbortPolicy​ 抛出 RejectedExecutionException​来拒绝新任务的处理。

  • CallerRunsPolicy​:调用执行自己的线程运行任务,由主线程自己来执行这个任务。(不允许丢弃任务适合该策略)

不常见策略(了解既可):

  • ThreadPoolExecutor.DiscardPolicy​:不处理新任务,直接丢弃掉。
  • ThreadPoolExecutor.DiscardOldestPolicy​:此策略将丢弃最早的未处理的任务请求。
📌Springboot下使用示例

当您使用ThreadPoolTaskExecutor​配置线程池时,可以参考以下示例代码:

ThreadPoolConfig​类通过@Configuration​注解标记为配置类,并定义了一个名为taskExecutor​的Bean,类型为ThreadPoolTaskExecutor​。在taskExecutor()​方法中,设置了线程池的核心线程数为10,最大线程数为20,队列容量为30,线程名前缀为"MyThread-",然后调用initialize()​方法初始化线程池,并返回配置好的ThreadPoolTaskExecutor​实例

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); // 设置核心线程数
        executor.setMaxPoolSize(20); // 设置最大线程数
        executor.setQueueCapacity(30); // 设置队列容量
        executor.setThreadNamePrefix("MyThread-"); // 设置线程名前缀
        executor.initialize(); // 初始化线程池
        return executor;
    }
}

异步任务的地方注入TaskExecutor Bean,并调用其execute()方法来提交任务:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    public void executeAsyncTask() {
        taskExecutor.execute(() -> {
            // 执行异步任务的逻辑
            System.out.println("Async task executed by thread: " + Thread.currentThread().getName());
        });
    }
}


然而,也有一些特殊场景下可能需要手动创建线程池实例:

  1. 定制化需求:如果需要对线程池进行高度定制,例如设置特定的线程池参数或使用特殊的线程工厂等,可能需要手动创建线程池实例。
  2. 独立使用:某些情况下,线程池只在一个特定的类或模块中使用,并且不需要在整个应用中共享,这时候手动创建线程池可能更合适。

大多数情况下建议将线程池实例交给Spring容器管理,以便统一管理和便于集成;如果手动创建了线程池实例,建议在某个特定的时机手动调用线程池的shutdown()​方法来优雅地关闭线程池,释放资源。

但这个特定时机怎么定义?使用CountDownLatch​或许可以符合你的场景。

CountDownLatch​的使用

CountDownLatch​ 的作用就是 允许 多个线程阻塞在一个地方,直到所有线程的任务都执行完毕。那么手动创建的线程就可以通过shutdown()​方法来优雅地关闭线程池了。

package com.fjh.demo.thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * @ClassName: CustomThreadPoolExample
 * @Description: TODO 手动自定义创建线程池,CountDownLatch使用场景
 * @Author: fengjiahao
 * @Date: 2024/6/15 21:26
 */
public class CustomThreadPoolExample {

    public static void main(String[] args) throws InterruptedException {
        int numThreads = 5;
        // 核心线程数
        int corePoolSize = 3;
        // 最大线程数
        int maxPoolSize = 5;
        // 线程空闲时间
        long keepAliveTime = 10;
        // 任务队列,使用有界队列ArrayBlockingQueue
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize, // 核心线程数
                maxPoolSize, // 最大线程数
                keepAliveTime, // 线程空闲时间
                TimeUnit.SECONDS, // 时间单位
                new ArrayBlockingQueue<>(3) // 任务队列
        );
        CountDownLatch latch = new CountDownLatch(numThreads);
        for (int i = 0; i < numThreads; i++) {
            int finalI = i;
            executor.execute(() -> {
                try {
                    System.out.println("Thread【"+ finalI +"】 started execute: " + Thread.currentThread().getName());
                    Thread.sleep(2000); // 模拟线程执行任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    latch.countDown(); // 每个线程执行完成后调用countDown方法
                }
                System.out.println("Thread finished: " + Thread.currentThread().getName());
            });
        }
        latch.await(); // 等待所有线程执行完成
        System.out.println("All threads have finished. Continuing main thread.");
        executor.shutdown(); // 关闭线程池
    }
}

☕最后

其实java8中有更加优雅的方式处理这种场景CompletableFuture​,有兴趣的同学可以去了解下🙂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1827130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

问:IP写作如何商业化?

这个问题也是很多朋友&#xff0c;或者新手小白问的最多的问题&#xff0c; 毕竟我们做副业都是为了挣钱嘛&#xff0c; 那么&#xff0c;回到问题&#xff0c;IP写作如何商业化&#xff1f; 这个问题其实对于我现在要日更的目标来说为时尚早&#xff0c;不过也可以先了解一下。…

Javaweb登录校验

登录校验 JWT令牌的相关操作需要添加相关依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>一、摘要 场景&#xff1a;当我们想要访问一个网站时&am…

如何用AI提高产品经理的工作效率

最近我跟几个产品经理聊天&#xff0c;发现有些人居然还没有使用过ChatGPT、MidJourney、NotionAI 等AI工具。 产品经理有个重要的素质是好奇心&#xff0c;好奇心能够帮助产品经理发现新机会、了解用户需求、学习新知识和探索竞争对手&#xff0c;从而更好地完成产品开发和管…

mediamtx流媒体服务器测试

MediaMTX简介 在web页面中直接播放rtsp视频流&#xff0c;重点推荐&#xff1a;mediamtx&#xff0c;不仅仅是rtsp-CSDN博客 mediamtx github MediaMTX(以前的rtsp-simple-server)是一个现成的和零依赖的实时媒体服务器和媒体代理&#xff0c;允许发布&#xff0c;读取&…

android13 应用冷启动

1 概述 launcher 通过binder到systemserver中atms中发送startActivity请求 startProcess向zygote发送启动新进程请求 zygote收到请求&#xff0c;fork新进程并调用ActivityThread的main初始化 新进程启动&#xff0c;发送attachApplication给ams&#xff0c;告诉他新进程启动…

C++ 44 之 指针运算符的重载

#include <iostream> #include <string> using namespace std;class Students04{ public:int m_age;Students04(int age){this->m_age age;}void showAge(){cout << "年龄是&#xff1a; " << this->m_age << endl;}~Students0…

155. 最小栈 力扣 python 空间换时间 o(1) 腾讯面试题

设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。int get…

RestTemplate远程请求的艺术

1 简说 编程是一门艺术,追求优雅的代码就像追求优美的音乐。 很多有多年工作经验的开发者,在使用RestTemplate之前常常使用HttpClient,然而接触了RestTemplate之后,却愿意放弃多年相处的“老朋友”,转向RestTemplate。那么一定是RestTemplate有它的魅力,有它的艺术风范。…

CCAA质量管理【学习笔记】​​ 备考知识点笔记(三)质量管理方法与常见工具

第二部分 质量管理领域专业知识 《质量管理体系基础考试大纲》中规定的考试内容&#xff1a; 3.2 质量管理领域专业知识 a) 了解质量管理方法与工具相关知识&#xff0c;包括&#xff1a; 质量管理方法与工具的内涵与作用、发展历程与应用现状、分类与选择常用的应用软件…

使用 Vue CLI 脚手架生成 Vue 项目

最近我参与了一个前端Vue2的项目。尽管之前也有过参与Vue2项目的经验&#xff0c;但对一些前端Web技术并不十分熟悉。这次在项目中遇到了很多问题&#xff0c;所以我决定借此机会深入学习Vue相关的技术栈。然而&#xff0c;直接开始深入钻研这些技术可能会显得枯燥&#xff0c;…

随笔-来了,安了

依照领导定的规矩&#xff0c;周五又去了分公司&#xff0c;赋能一线去了。到了地方就是开会->现场解决问题->干饭->开会过需求、提供解决方案&#xff0c;充实得厉害。强度也不小&#xff0c;中午干的一大碗饭&#xff0c;到五点就饿了。 六点带着分公司催着上线的需…

jupyter notebook中使用不同的anaconda环境及常用conda命令

conda命令 在jupyter notebook中使用不同的anaconda环境其他常用conda命令 在jupyter notebook中使用不同的anaconda环境 创建环境 myenvname 需替换为自己的环境名称 conda create --name myenvname python3.7激活环境 conda activate myenvname 在该环境中安装Jupyter N…

MongoDB~事务了解;可调一致性模型功能与因果一致性模型功能分析

背景 MongoDB 从 3.0版本引入 WiredTiger 存储引擎之后开始支持事务&#xff0c;MongoDB 3.6之前的版本只能支持单文档的事务&#xff0c;从 MongoDB 4.0版本开始支持复制集部署模式下的事务&#xff0c;从 MongoDB 4.2版本开始支持分片集群中的事务。 根据官方文档介绍&…

C++11 move左值转化为右值

单纯的左值只能用左值引用和右值只能用右值引用有些局限&#xff0c;在一些情况下&#xff0c;我们也需要对左值去调用右值引用&#xff0c;从而实现将左值里的内容转移到右值中 标准定义&#xff1a; 功能就是将一个左值强制转化为右值&#xff0c;然后实现移动语义 注意&…

IP地址、子网掩码、网段、网关

前面相同就是在同一个网段 如果子网掩码和网络号相与的结果是一样的&#xff0c;那么他们就在同一个子网 IP地址、子网掩码、网络号、主机号、网络地址、主机地址以及ip段/数字-如192.168.0.1/24是什么意思?_掩码248可以用几个ip-CSDN博客

CTFshow之RCE代码命令远程执行第29关到第40关详细讲解。一定教会

不在沉默中崛起&#xff0c;便在沉默中变态 --莫迪大仙 引言&#xff1a;最近学习没有头绪&#xff0c;想着把ctf随便刷一刷&#xff0c;过过瘾&#xff0c;试着看能不能每条10到15道题目&#xff0c;并且写下相关的学习记录&#xff0c;持续十天&#xff01;今天是RCE板块29关…

解决 kali 中使用 vulhub 拉取不到镜像问题

由于默认情况下&#xff0c;访问的镜像是国外的&#xff0c;而从 2023 年开始&#xff0c;docker 的镜像网站就一直访问不了&#xff0c;所以我们可以把镜像地址改成国内的阿里云镜像地址。 1、在 cd /etc/docker/目录下创建或修改daemon.json文件 sudo touch daemon.json 2、在…

统计信号处理基础 习题解答10-13

题目&#xff1a; 利用矩阵求逆引理&#xff0c;证明&#xff08;10.32&#xff09;和&#xff08;10.33&#xff09;。提示&#xff1a;首先证明&#xff08;10.33&#xff09;然后利用它来证明&#xff08;10.32&#xff09; 解答&#xff1a; 由&#xff08;10.28&#xf…

【TypeScript】类型兼容(协变、逆变和双向协变)

跟着小满zs 学习 ts&#xff0c;原文&#xff1a;学习TypeScript进阶类型兼容_typescript进阶阶段类型兼容 小满-CSDN博客 类型兼容&#xff0c;就是用于确定一个类型是否能赋值给其他的类型。如果A要兼容B 那么A至少具有B相同的属性。 // 主类型 interface A {name: string,a…

LVS-DR模式详解:提升网站性能的最佳解决方案

LVS-DR模式原理 用户请求到达Director Server&#xff1a; 用户请求到达Director Server&#xff08;负载均衡服务器&#xff09;&#xff0c;数据包首先到达内核空间的PREROUTING链。数据包源IP&#xff1a;CIP&#xff0c;目标IP&#xff1a;VIP&#xff0c;源MAC&#xff1a…