Java 并发编程<13>-ThreadPoolExecutor的springboot应用

news2024/9/24 23:30:43

Java 并发编程<13>-ThreadPoolExecutor的springboot应用

Java并发编程<10>安全集合

......

Java 并发编程<1>-线程实现的方式

线程池简介

a .为什么使用线程池

    降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;

    提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;

    方便线程并发数的管控,因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换(cpu切换线程是有时间成本的(需要保持当前执行线程的现场,并恢复要执行线程的现场)

    提供更强大的功能,延时定时线程池

b.线程池为什么需要使用队列

    因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换。

    创建线程池的消耗较高或者线程池创建线程需要获取mainlock这个全局锁,影响并发效率,阻塞队列可以很好的缓冲

c. 线程池为什么要使用阻塞队列

    阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源,当队列中有任务时才唤醒对应线程从队列中取出消息进行执行。

    使得在线程不至于一直占用cpu资源。(线程执行完任务后通过循环再次从任务队列中取出任务进行执行,代码片段如:while (task != null || (task = getTask()) != null) {})。

d.如何配置线程池

CPU密集型任务

    尽量使用较小的线程池,一般为CPU核心数+1。 因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,会造成CPU过度切换

IO密集型任务

    可以使用稍大的线程池,一般为2*CPU核心数。IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候有其他线程去处理别的任务,充分利用CPU时间

混合型任务

     可以将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理。 只要分完之后两个任务的执行时间相差不大,那么就会比串行执行来的高效因为如果划分之后两个任务执行时间有数据级的差距,那么拆分没有意义。

     因为先执行完的任务就要等后执行完的任务,最终的时间仍然取决于后执行完的任务,而且还要加上任务拆分与合并的开销,得不偿失。

execute和submit

execute()和submit()方法

1、execute(),执行一个任务,没有返回值。

2、submit(),提交一个线程任务,有返回值。

    submit(Callable<T> task)能获取到它的返回值,通过future.get()获取(阻塞直到任务执行完)。一般使用FutureTask+Callable配合使用

submit(Runnable task, T result)能通过传入的载体result间接获得线程的返回值。

    submit(Runnable task)则是没有返回值的,就算获取它的返回值也是null

Future.get()方法会使取结果的线程进入阻塞状态,直到线程执行完成之后,唤醒取结果的线程,然后返回结果。

springboot线程池示例一

    如果不自定义异步方法的线程池默认使用SimpleAsyncTaskExecutor。SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。并发大的时候会产生严重的性能问题。

    SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。

    SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方

  ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类

    SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类

ThreadPoolTaskExecutor:最常使用,推荐。其实质是对java.util.concurrent.ThreadPoolExecutor的包装

定义通用线程池,service直接使用

@Configurationpublic class ThreadPoolTaskConfig {    //cpu 核心数量    public static final int cpuNum = Runtime.getRuntime().availableProcessors();    /**     - 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,     - 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;     - 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝     */    /** 核心线程数(默认线程数) */    private static final int corePoolSize = cpuNum;    /** 最大线程数 */    private static final int maxPoolSize = cpuNum+1;    /** 允许线程空闲时间(单位:默认为秒) */    private static final int keepAliveTime = 60;    /** 缓冲队列大小 */    private static final int queueCapacity = 100;
    @Bean    public ExecutorService getThreadPool(){        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(                corePoolSize,                maxPoolSize,                keepAliveTime,                TimeUnit.SECONDS,                new LinkedBlockingQueue(queueCapacity),                Executors.defaultThreadFactory());        return threadPoolExecutor;    }}

service中使用

@Slf4j@Servicepublic class AsyncService implements IAsyncService {   @Autowired   private ExecutorService threadPoolExecutor;   @Override   public void executeAsync() {        threadPoolExecutor.execute(()->{            log.info("threadPoolExecutorexecute");            try {                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }        });    }}

controller

@RestControllerpublic class AsyncController {    @Autowired    private IAsyncService iAsyncService;    @GetMapping("/getAsync")    public void asyncMethod(){        iAsyncService.executeAsync();    }}执行结果如下:可以看到线程池起作用了2022-06-03 09:02:49.535 [http-nio-8081-exec-9] INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring FrameworkServlet 'dispatcherServlet'2022-06-03 09:02:49.903 [pool-2-thread-1] INFO  com.converter.service.impl.AsyncService - threadPoolExecutor execute2022-06-03 09:02:51.825 [pool-2-thread-2] INFO  com.converter.service.impl.AsyncService - threadPoolExecutor execute2022-06-03 09:02:52.012 [pool-2-thread-3] INFO  com.converter.service.impl.AsyncService - threadPoolExecutor execute2022-06-03 09:02:52.216 [pool-2-thread-4] INFO  com.converter.service.impl.AsyncService - threadPoolExecutor execute2022-06-03 09:02:52.903 [pool-2-thread-1] INFO  com.converter.service.impl.AsyncService - threadPoolExecutor execute2022-06-03 09:02:54.826 [pool-2-thread-2] INFO  com.converter.service.impl.AsyncService - threadPoolExecutor

springboot线程池示例二

     Spring 通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor实现一个基于线程池的TaskExecutor,

还得需要使用@EnableAsync开启异步,并通过在需要的异步方法那里使用注解@Async声明是一个异步任务

利用Spring注解使用线程池 

@EnableAsync@Configurationpublic class ThreadTestConfig {@Bean  //spring中@Async默认使用Bean Name为executor的线程池public Executor taskExecutor() {    ThreadPoolExecutor pool = new ThreadPoolExecutor(              corePoolSize,              maxPoolSize,              keepAliveTime,              TimeUnit.SECONDS,              new LinkedBlockingQueue(queueCapacity),              Executors.defaultThreadFactory());    return pool;}@Async默认使用Bean Name为executor的线程池。也可以根据Bean Name指定特定线程池@Async("taskExecuter")public void executeAsync() {    ......}

service​​​​​​​

@Slf4j@Servicepublic class AsyncService implements IAsyncService {
    @Autowired    private ExecutorService threadPoolExecutor;    @Override    @Async    public void executeAsync() {        log.info("executeAsync");        try {            Thread.sleep(2000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

controller​​​​​

@RestControllerpublic class AsyncController {    @Autowired    private IAsyncService iAsyncService;    @GetMapping("/getAsync")    public void asyncMethod(){        iAsyncService.executeAsync();    }}

springboot线程池事务问题

    在@Async标注的方法,同时也使用@Transactional进行标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。

那该如何给这些操作添加事务管理呢?

可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional

    方法A, 使用了@Async/@Transactional来标注,但是无法产生事务控制的目的。

    方法B, 使用了@Async来标注,B中调用了C、D,C/D分别使用@Transactional做了标注,则可实现事务控制的目的。

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

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

相关文章

基于Surf+GTM的图像配准和拼接算法matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 SIFT采用的是DoG图像&#xff0c;而SURF采用的是Hessian矩阵&#xff08;SURF算法核心&#xff09;行列式近似值图像。在数学中&#xff0c;Hessian矩阵是一个自变量为向量的实值函数的二阶偏导数…

计算机网络(自顶向下)学习笔记——传输层

第三章—传输层 传输层位于应用层和网络层之间&#xff0c;是分层的网络体系结构中重要的部分&#xff0c;该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。在这里我们将讨论两个大的问题&#xff1a;将网络层在不同端系统之间的通信服务扩充到运行在…

机器学习-PCA主成份分析详细解说及代码实现

本站原创文章&#xff0c;转载请说明来自《老饼讲解-机器学习》ml.bbbdata.com 目录 一. PCA主成分分析思想介绍 1.1 主成份分析思想 1.2 什么是主成份 二. PCA主成分分析的数学描述 2.1 主成份分析的数学表达 2.2 主成份系数矩阵A的约定 2.3 主成份分析需要输出什么 三…

Linux网络编程(一)——基础篇

目录 一、网络结构模式 &#xff08;一&#xff09;C/S结构 &#xff08;二&#xff09;B/S结构 二、MAC地址 三、IP地址 &#xff08;一&#xff09;IP地址编址方式 A类IP地址 B类IP地址 C类IP地址 D、E类IP地址 特殊的网址 IP分类的优缺点 &#xff08;二&#x…

解决org.apache.jasper.JasperException: 无法为JSP编译类

1.问题描述 org.apache.jasper.JasperException: 无法为JSP编译类: 在运行java web项目时&#xff0c;启动tomcat服务器报这样的操作&#xff0c;一般就是tomcat版本跟jdk版本不兼容的问题。我用的是jdk17&#xff0c;经过查阅相关资料得出一般使用jdk8就可以解决此类问题 2.…

微信小程序 | 小程序配置和架构

&#x1f5a5;️ 微信小程序 专栏&#xff1a;小程序配置和架构 &#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; ✨ 个人主页&#xff1a;CoderHing的个人主页 &#x1f340; 格言: ☀️ 路漫漫其修远兮,吾将上下而求索☀️ &#x1f44…

JavaScript:cookie和storage

cookie 用于客户端存储会话信息。在浏览器中会对cookie做一些限制&#xff1a; ❑ 不超过300个cookie&#xff1b; ❑ 每个cookie不超过4096字节&#xff1b; ❑ 每个域不超过20个cookie&#xff1b; ❑ 每个域不超过81920字节。 每个域能设置的cookie总数也是受限的&#xf…

(5)Pytorch数据处理

Pytorch 数据处理 要点总结 1、功能 Dataset&#xff1a;准备数据集&#xff0c;一般会针对自己的数据集格式重写Dataset&#xff0c;定义数据输入输出格式 Dataloader&#xff1a;用于加载数据&#xff0c;通常不用改这部分内容 2、看代码时请关注 Dataloader中collate_fn 传入…

分布式部署:第一章:zookeeper集群和solrcloud及redisCluster集群搭建

2.1 Zookeeper集群简介 2.1.1为什么搭建Zookeeper集群 大部分分布式应用需要一个主控、协调器或者控制器来管理物理分布的子进程。目前&#xff0c;大多数都要开发私有的协调程序&#xff0c;缺乏一个通用机制&#xff0c;协调程序的反复编写浪费&#xff0c;且难以形成通用、…

17、基于Mybaits、Vue、axios、Element-ui的JavaWeb项目

目录 1、项目功能介绍 ​编辑 2、环境准备 创建项目 准备数据库 准备Mybatis核心配置文件 创建实体类与Mapper映射文件 补全项目结构 1、在pom.xml中导入相关依赖 2、导入axios、vue的js文件 3、导入Element-ui 3、查询所有功能的实现 3.1、后端的实现 3.1.1、d…

【人工智能与机器学习】——朴素贝叶斯与支持向量机(学习笔记)

&#x1f4d6; 前言&#xff1a;朴素贝叶斯&#xff08;Naive Bayes&#xff09;和支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是两种不同的机器学习算法&#xff0c;它们都用于分类。朴素贝叶斯算法基于贝叶斯定理来进行分类&#xff0c;它是一…

内存优化之掌握 APP 运行时的内存模型

在上一章&#xff0c;我们已经从操作系统的维度了解了一个进程的内存模型。这一节&#xff0c;我们将维度继续上升&#xff0c;从应用层出发看看一个 App 运行时的内存模型是怎样的。从 App 运行时的内存模型中我们可以知道导致内存增长的源头&#xff0c;从源头出发&#xff0…

【RCNN系列】Faster RCNN论文总结及源码

目标检测论文总结 【RCNN系列】 RCNN Fast RCNN Faster RCNN 文章目录目标检测论文总结前言一、Pipeline二、模型设计1.RPNHead2.Anchors3.RPN&#xff08;Region Proposal Networks&#xff09;4.RPN正负样本划分阈值5.训练策略三、总结前言 一些经典论文的总结。 一、Pipel…

RK3568平台开发系列讲解(驱动基础篇)Linux内核面向对象思想之继承

🚀返回专栏总目录 文章目录 一、私有指针二、抽象类三、接口沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在面向对象编程中,封装和继承其实是不分开的:封装就是为了更好地继承。我们将几个类共同的一些属性和方法抽取出来,封装成一个类,就是为了通过继承最大化…

【云原生】devops之jenkins中pipeline语法(2)

前言&#xff1a; pipeline语法分类一般来说&#xff0c;有四种。分别是环境配置、阶段步骤、行为动作、逻辑判断。 二、阶段步骤 &#xff08;1&#xff09;post 根据pipeline块或者stage块&#xff08;阶段&#xff09;完成的状态来进行一个或者多个附加步骤&#xff08;取决…

搭建高性能数据库服务⭐《Sharding-JDBC+Canal》⭐

本文主要记录本周的学习内容&#xff0c;搭建mysql的高性能数据库服务 源于 现最多被使用的数据库还是Msql&#xff0c;而MySQL本身不是一种分布式型数据库&#xff0c;在高性能要求下&#xff0c;简单的主从、复制已无法满足高性能要求。 而本文主要在提供读者一种高性能方案…

Java学习之equals方法练习

目录 第一题 题目要求 我的代码 创建Person类 main类 结果 重写equals 重写后的结果 老师代码 思路 结果 总结 Interger类 源代码 String类 源代码 第二题 运行结果 第三题 知识点 运行结果 第一题 题目要求 判断两个 Person 对象的内容是否相等&#xff0c;…

SQL开窗函数之基本用法和聚合函数

开窗函数 当我们需要进行一些比较复杂的子查询时&#xff0c;聚合函数就会非常的麻烦&#xff0c;因此可以使用开窗函数进行分组再运用函数查询。窗口函数既可以显示聚集前的数据&#xff0c;也可以显示聚集后的数据&#xff0c;可以在同一行中返回基础行的列值和聚合后的结果…

python之模块使用

目录 一、模块 二、标准模块 collections模块 三、异常处理 四、文件操作 一、模块 Python 模块(Module)&#xff0c;是一个 Python 文件&#xff0c;以 .py 结尾&#xff0c;包含了 Python 对象定义和Python语句。 模块让你能够有逻辑地组织你的 Python 代码段。 新建util…

day17【代码随想录】找出字符串中第一个匹配项的下标 、重复的子字符串

文章目录前言一、找出字符串中第一个匹配项的下标&#xff08;力扣28&#xff09;二、重复的子字符串&#xff08;力扣459&#xff09;前言 1、找出字符串中第一个匹配项的下标 2、重复的子字符串 一、找出字符串中第一个匹配项的下标&#xff08;力扣28&#xff09; 给你两个…