进程和线程的比较
目录
一、前言
二、Linux查看进程、线程
2.1 Linux最大进程数
2.2 Linux最大线程数
2.3 Linux下CPU利用率高的排查
三、线程的实现
四、上下文切换
五、总结
一、前言
进程是程序执行相关资源(CPU、内存、磁盘等)分配的最小单元,是一系列线程的集合,进程之间相互独立,有自己的内存空间;线程是CPU资源分配的最小单元,线程需要的资源更少,可以看做是一种轻量级的进程,线程会共享进程中的内存,但线程使用独立的栈、程序计数器,线程相互通信更加方便。
在项目开发中,经常会用到线程以及多线程功能来实现异步任务处理等。项目上线之后,如果出现服务CPU高的异常情况,那么这个时候就需要借助Linux(因为一般情况服务都是使用Linux)查看进程、线程来定位最终的问题。
二、Linux查看进程、线程
2.1 Linux最大进程数
Linux中进程可创建的实际值通过进程标识值(process identification value)-PID来标示,可以使用
cat /proc/sys/kernel/pid_max 查看系统中可以创建的进程数实际值

可以使用ulimit命令修改最大限制值,
ulimit -u 1024
如果要修改kernel.pid_max的值,需要使用
sysctl -w kernel.pid_max=1024
2.2 Linux最大线程数
用ulimit -s可以查看默认的线程栈大小,一般情况下,这个值是8M=8192KB

不过Java程序受JVM堆空间的限制,比如以下代码
public class ThreadExample extends Thread{public static void main(String[] args) {for(int i = 0; i < 100000; i++){ThreadExample myThread = new ThreadExample(i);myThread.start();}}private Integer threadNo;ThreadExample(Integer threadNo){threadNo = threadNo;System.out.println("ThreadNo = " + threadNo);}@Overridepublic void run(){while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
在idea上设置-Xmx1m,启动运行程序,创建出部分线程后,会报OutOfMemoryError错误

2.3 Linux下CPU使用率高的排查
示例代码如下,这段代码可以明显判断出来在while(true){count++;}的地方,会占用很高的CPU使用率,那么如果代码已经上线了,在生产上,我们如何来判断哪里出问题了呢?
public class CpuRatioExample extends Thread{private Integer count = 0;public static void main(String[] args) {CpuRatioExample cpuRatioExample = new CpuRatioExample();cpuRatioExample.start();}@Overridepublic void run(){while(true){count++;}}
}
第一步:运行编译后的class
java CpuRatioExample
![]()
程序运行之后,我们发现CPU使用率过高,这个时候,我们需要排查是哪个代码导致的,一般情况生产系统上都会做CPU、磁盘等基础设施的监控。
第二步:CPU使用率过高排查
top 命令查看哪个进程CPU使用率高

使用top命令发现 PID 1822的CPU占用异常,再进一步查找哪个线程导致的,
top -H -p pid 可以查看哪个线程cpu过高

第三步:使用jstack命令保存栈信息
jstack 1822 > 1822.stack
并分析栈信息,查找 1878线程对应的栈信息

stack信息是以16进制显示的, 所以需要将CPU使用率高的线程1878转换为十六进制 756;定位到在CpuRationExample的17行代码运行,结合源代码,定位了最终问题。
三、线程的实现
3.1 单线程的实现方式
3.1.1 Thread
public class ThreadExample extends Thread{public static void main(String[] args) {for(int i = 0; i < 100000; i++){ThreadExample myThread = new ThreadExample(i);myThread.start();}}private Integer threadNo;ThreadExample(Integer threadNo){threadNo = threadNo;System.out.println("ThreadNo = " + threadNo);}@Overridepublic void run(){while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
这种方式很简单,但是不支持多重继承,所以不能继承其他类。
3.1.2 Runnable
public class ThreadExample implements Runnable{public static void main(String[] args) {for(int i = 0; i < 100000; i++){ThreadExample myThread = new ThreadExample(i);new Thread(myThread).start();}}private Integer threadNo;ThreadExample(Integer threadNo){threadNo = threadNo;System.out.println("ThreadNo = " + threadNo);}@Overridepublic void run(){while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
这种方式比继承Thread类更灵活,因为一个类可以实现多个接口。
3.1.3 FetureTask
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class ThreadExample {public static void main(String[] args) {FutureTask<Integer> futureTask = new FutureTask<>(() -> {// 异步执行的任务return 1;});new Thread(futureTask).start();try {// 获取异步执行的结果int result = futureTask.get();System.out.println("result = " + result);} catch (InterruptedException | ExecutionException e) {// 处理异常}}
}
3.2 线程池的实现方式
有关线程池的,后续再详细介绍。
3.2.1 使用Executors类创建线程池
Executors.newFixedThreadPool(int nThreads):创建一个固定大小的线程池。
Executors.newCachedThreadPool():创建一个可以缓存线程的线程池。
Executors.newSingleThreadExecutor():创建一个单线程化的线程池。
3.2.2 使用ThreadPoolExecutor类创建线程池
ThreadPoolExecutor是一个更底层的类,允许开发者更精细地控制线程池的行为,比如:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 5, // corePoolSize 10, // maximumPoolSize 60L, // keepAliveTime TimeUnit.SECONDS, // unit new LinkedBlockingQueue<Runnable>() // workQueue
);
四、上下文切换
多线程和单线程的选择往往取决于具体的应用场景和需求,单线程是一次只做一件事,按照顺序执行,而多线程可以同时处理多个任务,抢占更多的系统资源,但是也会出现上下文切换,有些时候,多线程的性能未必比单线程要好。比如以下这段代码
public class DemoApplication {public static void main(String[] args) {//运行多线程MultiThreadTester test1 = new MultiThreadTester();test1.Start();//运行单线程SerialTester test2 = new SerialTester();test2.Start();}static class MultiThreadTester extends ThreadContextSwitchTester {@Overridepublic void Start() {long start = System.currentTimeMillis();MyRunnable myRunnable1 = new MyRunnable();Thread[] threads = new Thread[3];//创建多个线程for (int i = 0; i < 3; i++) {threads[i] = new Thread(myRunnable1);threads[i].start();}for (int i = 0; i < 3; i++) {try {//等待一起运行完threads[i].join();} catch (InterruptedException e) {e.printStackTrace();}}long end = System.currentTimeMillis();System.out.println("multi thread exce time: " + (end - start) + "ms");System.out.println("counter: " + counter);}// 创建一个实现Runnable的类class MyRunnable implements Runnable {public void run() {while (counter < 100000000) {synchronized (this) {if(counter < 100000000) {increaseCounter();}}}}}}//创建一个单线程static class SerialTester extends ThreadContextSwitchTester{@Overridepublic void Start() {long start = System.currentTimeMillis();for (long i = 0; i < count; i++) {increaseCounter();}long end = System.currentTimeMillis();System.out.println("serial exec time: " + (end - start) + "ms");System.out.println("counter: " + counter);}}//父类static abstract class ThreadContextSwitchTester {public static final int count = 100000000;public volatile int counter = 0;public int getCount() {return this.counter;}public void increaseCounter() {this.counter += 1;}public abstract void Start();}
}

这段代码的测试结果是,单线程的性能高于多线程的性能,其主要原因就是多线程的上下文切换导致性能降低。
如果想要进一步分析上下文切换情况,可以使用vmstat和pidstat分析上下文切换情况。
五、总结
本文介绍了进程和线程的区别以及Java如何开发单线程、多线程;linux下最大进程数、线程数的限制,以及如何通过jstack排查CPU使用率高的问题。后续将专门针对多线程开发进行介绍。
相关文章:
进程和线程的比较
目录 一、前言 二、Linux查看进程、线程 2.1 Linux最大进程数 2.2 Linux最大线程数 2.3 Linux下CPU利用率高的排查 三、线程的实现 四、上下文切换 五、总结 一、前言 进程是程序执行相关资源(CPU、内存、磁盘等)分配的最小单元,是一…...
深入理解 Flink(四)Flink Time+WaterMark+Window 深入分析
Flink Window 常见需求背景 需求描述 每隔 5 秒,计算最近 10 秒单词出现的次数 —— 滑动窗口 每隔 5 秒,计算最近 5 秒单词出现的次数 —— 滚动窗口 关于 Flink time 种类 TimeCharacteristic ProcessingTimeIngestionTimeEventTime WindowAssign…...
科技创新领航 ,安川运动控制器为工业自动化赋能助力
迈入工业4.0时代,工业自动化的不断发展,让高精度运动控制成为制造业高质量发展的重要技术手段。北京北成新控伺服技术有限公司作为一家集工业自动化产品销售、系统设计、开发、服务于一体的高新技术企业,其引进推出的运动控制产品一直以卓越的…...
图像异或加密及唯密文攻击
异或加密 第一种加密方式为异或加密,异或加密的原理是利用异或的可逆性质,原始图像的像素八位bit分别与伪随机二进制序列异或,得到的图像就为加密图像。如下图对lena图像进行加密。 伪随机序列为一系列二进制代码,它受加密秘钥控…...
React Grid Layout基础使用
摘要 React Grid Layout是一个用于在React应用程序中创建可拖拽和可调整大小的网格布局的库。它提供了一个灵活的网格系统,可以帮助开发人员构建响应式的布局,并支持拖拽、调整大小和动画效果。本文将介绍如何使用React Grid Layout来创建自适应的布局。…...
第11章 1 文件及IO操作
文章目录 文件的概述及基本操作步骤 p151文件的写入操作 p152文件的读取操作及文件复制 p153文件的读取操作文件复制 with语句的使用 p154一维数据和二维数据的存储与读取 p155高维数据的存储和读取 p156os模块中的常用的函数 p157os.path模块中常用的函数 p158 文件的概述及基…...
Tomcat服务实例部署
目录 **Tomcat 由一系列的组件构成,其中核心的组件有三个:** 什么是 servlet? 什么是 JSP? Tomcat 功能组件结构: Container 结构分析: Tomcat 请求过程: ## Tomcat 服务部署 1.关闭防火墙…...
高精度彩色3D相机:开启崭新的彩色3D成像时代
3D成像的新时代 近年来,机器人技术的快速发展促使对3D相机技术的需求不断增加,原因在于,相机在提高机器人的性能和实现多种功能方面发挥了决定性作用。然而,其中许多应用所需的解决方案更复杂,仅提供环境的深度信息是…...
借助Gitee将typora图片上传CSDN
概述 前面已经发了一个如何借助Github将typora上的图片上传到csdn上,但这有个缺陷:需要科学上网才能加速查看已经上传到github上的图片,否则就会出现已经上传的图片,无法正常查看的问题 如何解决? 那就可以使用Gite…...
几件奇怪的事产生的疑团
1.记得当年在中国科技大学杨照华给我们上初等数论课(杨是北大毕业,闵嗣鹤教授的关门弟子,后来到华南师大任教),他说过“据华老(华罗庚)讲,希尔伯特最先解决华林问题的论文中用到二十…...
陶瓷碗口缺口检测-图像增强
图像增强 在采集图像的过程中,可能会有由于采集图像环境中光源照射不足,导致采集的图像对比度不足,图像视觉效果较暗的情况,可以通过直方图均衡化或者直方图规定化。如图a为原图像对比度低,图c为其直方图,…...
gitee创建远程仓库并克隆远程仓库到电脑
1、首先点加号新建一个仓库 2、输入仓库名,路径会自动填充,填写简单的仓库介绍,先选择私有,在仓库创建之后,可以改为开源 3、打开建好的仓库 4、复制仓库链接 5、打开一个文件夹(想要存储远程仓库的地址),在…...
3D人体姿态估计(教程+代码)
3D人体姿态估计是指通过计算机视觉和深度学习技术,从图像或视频中推断出人体的三维姿态信息。它是计算机视觉领域的一个重要研究方向,具有广泛的应用潜力,如人机交互、运动分析、虚拟现实、增强现实等。 传统的2D人体姿态估计方法主要关注通…...
Python异步编程|PySimpleGUI界面读取PDF转换Excel
目录 实例要求 原始pdf文件格式 输出xls文件格式 运行界面 完整代码 代码分析 遍历表格 布局界面 控件简介 写入表格 表格排序 事件循环 异步编程 实例要求 使用PySimpleGUI做一个把单位考勤系统导出的pdf文件合并输出Excel的应用,故事出自࿱…...
制造领域 基础概念快速入门介绍
1、基本背景知识 本定义结合国家标准文件有所发挥,仅供参考。 产品:是生产企业向用户或市场以商品形式提供的制成品; 成套设备:在生产企业一般不用装配工序连接,但用于完成相互联系的使用功能的两个或两个以上的产…...
小程序的完整开发流程?
小程序的完整开发流程可以分为以下几个步骤: 需求分析和设计:明确小程序的功能需求和设计思路,包括页面结构、交互逻辑等。 环境搭建:安装并配置开发工具,如微信开发者工具或其他小程序开发工具。 项目初始化&#x…...
【LV13 DAY16 轮询与中断】
轮询实现按键实验 #include "exynos_4412.h"int main() {//GPX1_1设置为输入模式//GPX1.CONGPX1.CON & (~ (0XF<<4));while(1){if(!(GPX1.DAT&(1<<1))){printf("key pressed\n");while(!(GPX1.DAT&(1<<1)));}else{}}return…...
Swoft - Bean
一、Bean 在 Swoft 中,一个 Bean 就是一个类的一个对象实例。 它(Bean)是通过容器来存放和管理整个生命周期的。 最直观的感受就是省去了频繁new的过程,节省了资源的开销。 二、Bean的使用 1、创建Bean 在【gateway/app/Http/Controller】下新建一个名为…...
【产品人卫朋】硬件产品经理:从入门到精通
目录 本文目录 1. 前言说明 2. 内容说明 3. 资料包说明 作者简介 本文目录 1. 前言说明 2. 内容说明 3. 资料包说明 1. 前言说明 本篇内容节选自实体书《硬件产品经理:从入门到精通》。 2. 内容说明 鉴于硬件产品的特殊性,不同产品阶段的时间间…...
swing快速入门(四十)JList、JComboBox实现列表框
注释很详细,直接上代码 上一篇 新增内容 🧧1.列表的属性设置与选项监听器 🧧2.下拉框的属性设置与选项监听器 🧧3.Box中组件填充情况不符合预期的处理方法 🧧4.LIst向Vector的转化方法 源码: package swing…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
