Java多线程导致CPU占用100%解决及线程池正确关闭方式

2023-11-08


前言

情景:1000万表数据导入内存数据库,按分页大小10000查询,多线程,15条线程跑。 使用了ExecutorService executor = Executors.newFixedThreadPool(15) 本地跑了一段时间后,发现电脑CPU逐渐升高,最后CPU占用100%卡死,内存使用也高达80%

一、cpu占用高排查问题

Debug 发现虽然创建了定长15的线程池,但是因为数据量大,在For中循环分页查询的List会持续加入LinkedBlockingQueue()
队列中每一个等待的任务,又加载了1万的数据。所以不管是线程数的CPU抢占,还是内存的消耗都是极高。
所以是不是能够控制等待队列LinkedBlockingQueue的上限就可以了。
在这里插入图片描述

二、解决办法

使用AtomicLong 统计线程是否完成,再执行executor.submit()提交新的任务导队列中。

伪代码如下:

代码如下(示例):

private AtomicLong threadNum = new AtomicLong(0);

public void init() throws Exception {
	ExecutorService executor = Executors.newFixedThreadPool(15);

	Integer total = accountMapper.selectCount(new QueryWrapper<>());
	Integer pageSize = 10000;  // 页大小
	Integer pageCount = (total + pageSize -1) / pageSize; // 总页数

	for (Integer start = 1; start <= pageCount; start++) {

		List<Account> list = accountMapper.selectPage(new Page<>(start, pageSize), query).getRecords();

		//等待线程任务完成,设置30,可令运行线程数为15,等待队列线程数为15
		while (threadNum.get() >= 30){
			Thread.sleep(5000);
		}

		//开启1个线程+1
		threadNum.incrementAndGet();
	
		executor.submit(() -> {

			try {
				// 处理业务
				dealMessage(list);
				// 任务完成 -1
				threadNum.decrementAndGet();
			} catch (Exception e) {
				e.printStackTrace();
			}

		});

	}
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.DAYS);

}

效果就是CPU保持在15~45%之间,内存占用也只有45%。

目前只想到这样的方式,控制等待队列LinkedBlockingQueue的上限,还有更好的方式请告知,感谢!

三、多线程关闭与令牌限流:

  1. 线程池必须关闭,main主线程才能结束(接口才会返回)finally { executorService.shutdown(); }
  2. 主线程等待保证多线程所有子线程任务执行完毕,再结束。 -> executorService.awaitTermination(1, TimeUnit.DAYS);
  3. semaphore 令牌限流控制fixedThread线程池,本例子就是最多同时拥有2个线程进行工作
  4. fixedThread.execute() fixedThread.submit() 的差别除了后者可以返回结果外,后者还会catch掉异常信息,无法抛到主线程中。

public static void main(String[] args) {
    final List<String> tableNames = new ArrayList<>();
    tableNames.add("a");
    tableNames.add("b");
    tableNames.add("c");
    tableNames.add("d");
    tableNames.add("e");
    tableNames.add("f");

    final Semaphore semaphore = new Semaphore(2);
    final ExecutorService fixedThread = Executors.newCachedThreadPool();
    for (final String tableName : tableNames) {
        //阻塞,获取令牌
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //do
        fixedThread.execute(() -> {  //can throw ex log
            final ExecutorService executorService = Executors.newCachedThreadPool();
            try {
                executorService.submit(() -> { //can't throw ex log
                    //int i = 1/0;
                    System.out.println("tableName2:" + tableName);
                });
                //int i = 1/0;
                System.out.println("tableName:" + tableName);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                executorService.shutdown();
                try {
                    executorService.awaitTermination(1, TimeUnit.DAYS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                semaphore.release();
                System.out.println("semaphore.release");
            }
        });
    }
    // 记得关闭线程池
    fixedThread.shutdown();
    try {
        fixedThread.awaitTermination(1, TimeUnit.DAYS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("主线程...");
}


打印结果:


tableName:b
tableName2:b
tableName:a
tableName2:a
semaphore.release
semaphore.release
tableName:d
tableName2:d
tableName:c
semaphore.release
tableName:e
tableName2:c
semaphore.release
tableName:f
tableName2:e
semaphore.release
tableName2:f
semaphore.release
主线程...


转载:https://www.cnblogs.com/levi125/p/13914883.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java多线程导致CPU占用100%解决及线程池正确关闭方式 的相关文章

  • Python爬虫深造篇(一)——多线程网页爬取

    一 前情提要 相信来看这篇深造爬虫文章的同学 大部分已经对爬虫有不错的了解了 也在之前已经写过不少爬虫了 但我猜爬取的数据量都较小 因此没有过多的关注爬虫的爬取效率 这里我想问问当我们要爬取的数据量为几十万甚至上百万时 我们会不会需要要等几
  • C# Task异步编程

    Task任务用法 Task用的是线程池 线程池的线程数量的有上限的 这个可以通过ThreadPool修改 我们经常会用到task run new task 和task factory startnew方法来创建任务 Task Factory
  • linux线程学习(二)

    上一个linux线程学习是不带锁的线程不安全形式 只要不用共享资源还是可以的 但实际工作中我们遇到的往往是需要保障线程的访问的 因此这里实现了一个简单的线程池 为线程池的实现提供思路 Status类封装了环境变量与锁 作为一种状态保障线程的
  • 如何正确使用线程池

    具体请参考原创 Java线程池实现原理及其在美团业务中的实践 Java 线程池及参数动态调节详解 一 为何要使用线程池 降低资源消耗 线程的创建和销毁会造成一定的时间和空间上的消耗 线程池可以让我们重复利用已创建的线程 提高响应速度 线程池
  • muduo库源码分析和总结

    陈硕大神的muduo库设计巧 但是难读懂 这里简单做个总结 注意回调函数太多 需仔细研究回调的传递和调用 两个核心梳理主线 EventLoopThreadPool start EventLoop runInLoop 其次陈硕认为网络编程的本
  • 线程池的使用与分析(ThreadPoolExcutors)

    开发中为什么使用线程池 1 降低资源的消耗 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗 2 提高响应速度 因为线程池中的线程数没有超过线程池的最大上限时 有的线程处于等待分配任务的状态 当任务来时无需创建新的线程就能执行 3
  • 线程池的主要处理流程及常用方法

    线程池的主要处理流程及常用方法 更多优秀文章 请扫码关注个人微信公众号或搜索 程序猿小杨 添加 一 主要处理流程 当调用线程池execute 方法添加一个任务时 threadPoolExecutor execute 具体代码如下 priva
  • 【Java线程】线程池的创建

    线程池装配类 线程池优雅停机控制 Configuration public class FeedBackExecutorConfig implements ApplicationListener
  • 常用线程池介绍

    线程池简介 1 线程池概念 线程池是首先创建一个线程 它们的集合成为线程池 使用线程池可以很好的提升性能 线程池在启动时即创建大量空闲的线程 程序将一个任务传给线程池 线程池就会启动一条线程来执行这个任务 执行线程完成后 该线程不会死亡 而
  • Java线程池execute()方法源码解析

    先看作者给出的注释来理解线程池到底有什么作用 Thread pools address two different problems they usually provide improved performance when execut
  • Java 多线程编程学习笔记(7月16号)

    文章目录 作者信息 前言 一 什么是线程 1 1 进程和线程 1 2 并发和并行 1 3 上下文切换 Context Switch 二 创建线程的三种方式 2 1 概述 2 2 继承Thread类 2 3 实现Runnable接口 2 4
  • Java基础知识-- Thread和线程池的具体使用

    Java Thread具体使用 1 直接创建匿名线程使用 new Thread public void run System out println Sub Thread Runnable start 2 使用Runnable包装待执行的任
  • C++11的半同步半异步线程池

    C 11的半同步半异步线程池 简介 同步队列 Take函数 Add函数 Stop函数 SyncQueue完整代码 线程池 主函数测试 简介 半同步半异步线程池用的比较多 实现也比较简单 其中同步层包括同步服务层和排队层 指的是将接收的任务排
  • python 线程池使用

    前段时间发现了一个 人工智能学习网站 通俗易懂 风趣幽默 分享一下给大家 学习链接 文章目录 线程池使用 1 线程池介绍 2 使用方法 2 1 threadpool 2 2 ThreadPoolExecutor submit as comp
  • Linux下线程池的代码

    此博客仅为了存放代码 Linux 加锁 线程池 头文件 include
  • python 多线程 线程池的四种实现方式

    python 线程池的四种实现方式 线程简述 一个程序运行起来后 一定有一个执行代码的东西 这个东西就是线程 一般计算 CPU 密集型任务适合多进程 IO密集型任务适合多线程 一个进程可拥有多个并行的 concurrent 线程 当中每一个
  • 用c99 写的简单线程池类

    include
  • JAVA使用线程池查询大批量数据

    前言 在开发过程中可能会碰到某些独特的业务 比如查询全部表数据 数据量过多会导致查询变得十分缓慢 虽然在大多数情况下并不需要查询所有的数据 而是通过分页或缓存的形式去减少或者避免这个问题 但是仍然存在需要这样的场景 比如需要导出所有的数据到
  • 线程池的使用实例

    线程池的使用实例 number 创建线程个数 创建线程池 ExecutorService cachedThreadPool Executors newCachedThreadPool 每次线程执行完毕 计数 1 当计数减到 0 之后 才能解
  • JAVA多线程执行,等待返回结果,再执行

    JAVA多线程执行 等待返回结果 再执行 1 实现callable接口 1 配置线程池 package com neusoft demo server config import org springframework context an

随机推荐

  • fastjson对泛型的反序列化

    文章目录 具体告警分析 告警影响 fastjson未指定泛型具体类型 fastjson TypeReference指定泛型具体类型 可以看到fastjson反序列化时IDEA提示告警 Unchecked assignment 怎么解决这个告
  • ubuntu+vscode构建c++开发调试环境

    1 vscode下载与安装 下载 Visual Studio Code Mac Linux Windows下载deb文件 运行指令安装vscode sudo dpkg i xxx deb 如果报 dpkg 错误 另外一个进程已经为 dpkg
  • python 3.7版本 打不开 python 3.8 保存的pickle文件

    1 问题描述 最近有一个pickle文件 当我使用python3 7 读取的时候报错 ValueError unsupported pickle protocol 5 查找原因发现是原始文件是用高版本的python解释器 比如3 8 保存的
  • 数据结构实验--表达式的后缀表示

    一 问题描述 表达式中包含运算对象 运算符和圆括号等 习惯上使用中缀表示 指运算符夹在两运算符对象中间 形式 计算表达式的值 涉及到运算符的优先级别 如先乘除后加减 括在一对圆括号中的子表达式必须先计算 因此 圆括号可视为特殊的运算符 具有
  • Linux--遇见的一些小错误

    一 问题 linux下运行出现 sh 1 pause not found 原因 在windows系统下 使用此语句 但linux不认识 system pause 解决方法 删去system pause 二 问题 编程时出现 Warning
  • Unity3D——AR小游戏

    文章目录 有趣的AR小游戏制作 环境准备 具体实现 替换Camera 上传识别卡 下载识别卡模型 编辑游戏对象 实验环境是否配置成功 导入Lean Touch脚本 制作成Android应用 游戏制作 实验结果 有趣的AR小游戏制作 环境准备
  • MySQL 5.1中文参考手册 - 学习笔记

    MySQL 5 1中文参考手册地址 http dev mysql com doc refman 5 1 zh index html 学习笔记及重要点 由于最近使用MySQL数据库的机会越来越多 所以看来这次要认真的学习一下了 以往只懂得皮毛
  • 线程-Linux下的轻量级进程

    首先我们知道 每个进程都是在各自独立的地址空间上运行 如果要同时完成好几个任务 比如你一边在下载软件 另一边在进行着其他的操作 那么试想一下 可不可以在一个进程里面把这几个事件同时进行呢 这里就要提到线程的概念了 但其实Linux中 并没有
  • Unity 实用代码 小工具

    Unity 实用代码 小工具 Unity 屏幕截图 全屏截图方法 全屏截图方法 带委托事件 自定义截图方法 自定义截图方法 带委托 延迟工具 携程延迟方法 携程延迟带委托方法 场景加载 场景加载 方法 场景加载方法 带委托 异步场景加载 方
  • Warning: This development build of composer is over 60 days old

    今天查看了一下服务器安装的Composer版本 报了一个警告 意思是安装已经超过60天了 需要执行 usr bin composer self update 升级到最新版本 然后我就执行了 再次查看版本确实更新到官方最新的1 7 3版本 但
  • PTA7(python3)

    python程序设计07 字符串与正则表达式 7 1 找最后的字符 30 分 7 2 重要的事情说N遍 20 分 7 3 号码牌的制作 10 分 7 4 统计字符串中指定字符的个数 30 分 7 5 字符串消除空格 30 分 7 6 统计指
  • 三分钟弄懂物联网流行协议——MQTT

    MQTT Message Queue Telemetry Transport 翻译成中文就是 遥测传输协议 其主要提供了订阅 发布两种消息模式 更为简约 轻量 易于使用 特别适合于受限环境 带宽低 网络延迟高 网络通信不稳定 的消息分发 属
  • C++中vector迭代器失效问题及其解决方法

    C 中vector迭代器失效问题及其解决方法 迭代器的主要作用就是让算法能够不用关心底层数据结构 其底层实际就是一个指针 或者是对指针进行了封装 比如 vector的迭代器就是原生态指针T 因此迭代器失效 实际就是迭代器底层对应指针所指向的
  • php socket error 111,php中的socket_connect上的“连接被拒绝”错误

    我试图将一些代码从perl转换为php Perl代码如下所示 my handle Connect port host 我试图使用socket在PHP中做同样的事情 我试过socket create和socket connect socket
  • Windows(10/11)端vscode开发、调试远程Linux(Ubuntu14.04)端c++ 开发环境部署步骤

    1 安装vscode 进入https code visualstudio com 即vsocde官网选择Windows x64版本下载并安装 安装过程中推荐勾选往右键菜单添加通过vscode打开文件夹的选项 2 vsocde插件安装 打开v
  • 《影响力》第七章:稀缺

    稀缺 物以稀为贵 稍纵即逝 越是得不到就越觉得香 这是为啥 至于是不是真的香 由于得不到 也不得而知 例如 我有一个朋友觉得佐佐木希如果能娶来做老婆是很香的 简直就是夫复何求 然而这世上当真有人会把女神娶回家然后出轨还家暴 这说来还真是让人
  • 判断点是否在任意多边形内(java)

    import java util ArrayList public class Test public static void main String args double px 113 0253 double py 23 98049 A
  • 文心一言和讯飞星火全面对比测试:(三)常识问题

    前文回顾 在 一 语言理解能力测试中 我们主要测试了两个大语言模型对复杂语义的理解 对文章情绪的识别 对文章进行摘要总结 对文章进行要素提取 测试结果表明 在语言理解能力上 除了有些问题他拒绝回答之外 讯飞星火的表现明显要好于文心一言 可以
  • 函数和windows对象 有惊喜✔

    一 函数 函数的定义 类似于Java中的方法 是完成特定任务的代码语句块 1 系统函数 eval lt 表达式 gt 得到一个文本框的值 表单 例 var sname eval doucment form sname value parse
  • Java多线程导致CPU占用100%解决及线程池正确关闭方式

    文章目录 前言 一 cpu占用高排查问题 二 解决办法 使用AtomicLong 统计线程是否完成 再执行executor submit 提交新的任务导队列中 三 多线程关闭与令牌限流 前言 情景 1000万表数据导入内存数据库 按分页大小