线程和进程
文章目录
- 进程和线程
- 进程
- 线程
- 案例
- 时间片概念
- 调度方式
- 线程的创建和启动
- 第一种创建方式
- 第二种创建方式(匿名内部类)
- 第三种创建方式(Runnable接口)
- main线程和t线程之间的关系
- 线程的名字
- 线程的优先级
- 线程状态
进程和线程
进程
在计算机中,进程代表了内存中正在运行的应用程序,计算机中的资源(cpu 内存 磁盘 网络等),会按照需求分配给每个进程,从而这个进程对应的应用程序就可以使用这些资源了。
在操作系统中,启动一个应用程序的时候,会有一个或多个进程同时被创建,这些进程其实就表示了当前这个应用程序,在系统中的资源使用情况以及程序运行的情况。如果关闭这个进程,那么对应的应用程序也就关闭了。
所以,进程就是在系统中,运行一个应用程序的基本单位。
线程
线程是进程中的一个代码执行单元,负责当前进程中代码程序的执行,一个进程中有一个或多个线程。
当一个进程中启动了多个线程去分别执行代码的时候,这个程序就是多线程程序。
案例
例如,当前我们去运行一个类的时候,会先启动JVM,这个JVM对于计算机来讲,就是一个
应用程序,所以同时系统中也会启动一个进程和这个JVM对应:
public class hello{public static void main(String[] args)throws Exception{System.out.println("hello");long time = 1000*100L;Thread.sleep(time);System.out.println("world");}
}
我们运行这个代码:
注意,代码中,输出hello之后,JVM并没有直接结束,而是让当前线程去休眠了100秒,所以这个时候JVM还在运行着,我们可以在任务管理器中,看到JVM对应的进程了
除此之外,我们还可以使用JDK中提供的工具,来查看JVM当前的运行情况,在cmd中输入jconsole,然后连接:
这里通过JDK自带的jconsole工具,可以检测到当前运行Hello这个类的时候,JVM的运行情况,包含内存的使用、线程的运行状态、类的加载等信息.
例如,查看当前JVM中执行main方法线程信:
(注意,这线程的名字就叫main,它是任务就是调用执行我们类中的main方法,所以,是一个名字叫main的线程,调用执行我们代码中的main方法)
时间片概念
时间片,当前一个线程要使用CPU的时候,CPU会分配给这个线程一小段时间(毫秒级别),这段时间就叫做时间片,也就是该线程允许使用CPU运行的时间,在这个期间,线程拥有CPU的使用权。
如果在一个时间片结束时,线程还在运行,那么这时候,该线程就需要停止运行,并交出CPU的使用
权,然后等待下一个CPU时间片的分配。
(在宏观上,一段时间内,我们感觉两个线程在同时运行代码,其实在微观中,这俩个线程在使用
一个CPU的时候,它们是交替着运行的,每个线程每次都是运行一个很小的时间片,然后就交出CPU使用权,只是它们俩个交替运行的速度太快了,给我们的感觉,好像是它们俩个线程在同时运行。)
调度方式
当俩个或多个线程使用一个CPU来运行代码的时候,在操作系统的内核中,就会有相应的算法来控制线程获取CPU时间片的方式,从而使得这些线程可以按照某种顺序来使用CPU运行代码,这种情况被称为线程调用。
常见的调度方式有两种:
- 时间片轮转
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。 - 抢占式调度
系统会让优先级高的线程优先使用 CPU(提高抢占到的概率),但是如果线程的优先级相同,那么会随机选择一个线程获取当前CPU的时间片。
(JVM中的线程,使用的为抢占式调度。)
线程的创建和启动
java.lang.Thread
是java中的线程类,所有的线程对象都必须是Thread类或其子类的实例。
每个线程的作用,就是完成我们给它指定的任务,实际上就是执行一段我们指定的代码。我们只需要在Thread 类的子类中重写 run 方法,把执行的代码写入到run方法中即可,这就是线程的执行任务
Java中通过继承Thread类来创建并启动一个新的线程的步骤如下:
- 定义 Thread 类的子类(可以是匿名内部类),并重写 Thread 类中的 run 方法, run 方法中的
代码就是线程的执行任务 - 创建 Thread 子类的对象,这个对象就代表了一个要独立运行的新线程
- 调用线程对象的 start 方法来启动该线程
第一种创建方式
package shixun;public class myTest {public static void main(String[] args) {MyThread myThread=new MyThread();myThread.start();}
}class MyThread extends Thread{@Overridepublic void run() {int x=0;while(true){String name = Thread.currentThread().getName();System.out.println("hello, ["+name+"] - "+(x++));try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}}}
}
第二种创建方式(匿名内部类)
package shixun;public class myTest {public static void main(String[] args) {Thread thread=new Thread(){@Overridepublic void run() {int x=0;while(true){String name = Thread.currentThread().getName();System.out.println("hello, ["+name+"] - "+(x++));try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}}}};thread.start();}
}
第三种创建方式(Runnable接口)
package shixun;public class myTest {public static void main(String[] args) {Thread thread=new Thread(new Runnable() {@Overridepublic void run() {int x=0;while(true){String name = Thread.currentThread().getName();System.out.println("hello, ["+name+"] - "+(x++));try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}}}},"线程的名字"); //第二个参数可以指定idthread.start();}
}
main线程和t线程之间的关系
在此过程中,main线程和t线程之间的关系是: main线程在执行main方法的过程中,创建并启动了t线程,并且t线程启动后,和main线程就没有关系了,这时候main线程和t线程都是自己独立的运行,并且他们俩个是要争夺CPU的时间片(使用权)的。
线程的名字
通过Thread类中的currentThread
方法,可以获取当前线程的对象,然后调用线程对象的getName
方法,可以获取当前线程的名字。 String name = Thread.currentThread().getName();
(注意,这里说的当前线程,指的是执行当前方法的线程,因为获取线程名字的代码肯定是写在某个方法中的,并且这个方法一定是由某个线程调用执行的。)
例如:
package shixun;public class myTest {public static void main(String[] args) {String name = Thread.currentThread().getName();System.out.println("执行当前main方法的线程是:"+name);Thread thread=new Thread(new Runnable() {@Overridepublic void run() {String name1 = Thread.currentThread().getName();System.out.println("执行当前run方法的线程是:"+name1);}});thread.start();}
}
(注意,一定要记得,start方法启动线程后,线程会自动执行run方法,千万不要直接调用run方法,这样就不是启动线程执行任务,而是普通的方法调用。)
默认情况下,主线程中,创建出的线程,它们的都会有一个默认的名字,如Thread-0 Thread-1
Thread-2等等,我们也可以创建线程对象的时候,给它设置一个指定的名字:
Thread t = new Thread("t线程");
//或者
Thread t = new Thread(new Runnable(){public void run(){//执行任务}
},"t线程");
//或者
Thread t = new Thread();
t.setName("t线程");
线程的优先级
线程的优先级使用int类型数字表示,最大是10,最小是1,默认的优先级是5。
当俩个线程争夺CPU时间片的时候:
优先级相同,获得CPU使用权的概率相同
优先级不同,那么高优先级的线程有更高的概率获取到CPU的使用权(只是有更高的概率,并不是一定能获取到)
例如:不设置优先级的情况下,t1和t2线程各自运行10000次循环,看哪个线程先运行完
package shixun;public class myTest {public static void main(String[] args) {Thread thread1=new Thread("t1线程"){@Overridepublic void run() {String name = Thread.currentThread().getName();for (int i = 0; i < 10000; i++) {}System.out.println(name+"线程执行完毕");}};Thread thread2=new Thread("t2线程"){@Overridepublic void run() {String name = Thread.currentThread().getName();for (int i = 0; i < 10000; i++) {}System.out.println(name+"线程执行完毕");}};System.out.println("t1线程的优先级:"+thread1.getPriority());System.out.println("t2线程的优先级:"+thread2.getPriority());thread1.start();thread2.start();}
}
(注意,默认情况下,俩个线程的优先级都是5,那个俩个线程争夺到CPU的使用权的概率一样,那么基本上俩个线程都有相同的概率先执行完10000次循环,其实t1先稍微占了那么一点点的优势,因为毕竟在主线程的代码中,先启动了t1先,然后又启动了t2线程)
然后设置优先级再来运行一下:
设置完t1和t2优先级之后,在运行结果中会明显看到优先级高的t2线程,会有更高的概率先执行完
代码。
线程状态
线程的状态分为以下几种:
线程状态 | 描述 |
---|---|
NEW(新建) | 线程刚被创建,还没调用start方法,或者刚刚调用了start方法,调用 start方法不一定"立即"改变线程状态,中间可能需要一些步骤才完成一个线程的启动。 |
RUNNABLE(可运行) | start方法调用结束,线程由NEW变成RUNNABLE,线程存活着,并尝试抢占CPU资源,或者已经抢占到CPU资源正在运行,这俩种情况的状态都显示为RUNNABLE |
BLOCKED(锁阻塞) | 线程A和线程B都要执行方法test,而且方法test被加了锁,线程A先拿到了锁去执行test方法,线程B这时候需要等待线程A把锁释放。这时候线程B就是处理BLOCKED |
WAITING(无限期等待) | 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入 Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。 |
TIMED_WAITING(有限期等待) | 和WAITING状态类似,但是有一个时间期限,时间到了,自己也会主动醒来 |
TERMINATED(终止) | run方法执行结束的线程处于这种状态。 |
其实 BLOCKED,WAITING,TIMED_WAITING 这三种都属于线程阻塞,只是触发的条件不同,以及从阻塞状态中恢复过来的条件也不同而已。
线程在这三种情况的阻塞下,都具备相同的特点:
1.线程不执行代码
2.线程也不参与CPU时间片的争夺
例如:一个线程,经历的最普通的过程如下:
package shixun;public class myTest {public static void main(String[] args) {Thread thread1=new Thread("t1线程"){@Overridepublic void run() {String name = Thread.currentThread().getName();for (int i = 0; i < 100000; i++) {}}};System.out.println(thread1.getState());thread1.start();System.out.println(thread1.getState());System.out.println(thread1.getState());System.out.println(thread1.getState());System.out.println(thread1.getState());System.out.println(thread1.getState());System.out.println(thread1.getState());}
}
刚创建好的线程对象,就是出于NEW的状态。
线程启动后,会出于RUNNABLE状态,这个RUNNABLE状态包含俩种情况:
1.就绪状态,此时这个线程没有运行,因为没有抢到CPU的执行权
2.运行状态,此时这个线程正在运行中,因为抢到CPU的执行权
相关文章:

线程和进程
文章目录 进程和线程进程线程案例 时间片概念调度方式线程的创建和启动第一种创建方式第二种创建方式(匿名内部类)第三种创建方式(Runnable接口)main线程和t线程之间的关系 线程的名字线程的优先级线程状态 进程和线程 进程 在计…...

【JavaEE】 简单认识CPU
🐵本篇文章将对cpu的相关知识进行讲解 一、认识CPU 下图是简略的冯诺依曼体系结构图 上图中,存储器用来存储数据,注意在存储器中都是以二进制的形式存储数据的,CPU就是中央处理器,其功能主要是进行各种算术运算和各种…...

《数字图像处理-OpenCV/Python》第17章:图像的特征描述
《数字图像处理-OpenCV/Python》第17章:图像的特征描述 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第17章:图像的特征描述 特征检测与匹配是计算机视觉的…...

考研数学什么时候开始强化?如何保证进度不掉队?
晚了。我是实在人,不给你胡乱吹,虽然晚了,但相信我,还有的救。 实话实说,从七月中旬考研数一复习完真的有点悬,需要超级高效快速... 数二的时间也有点紧张... 中间基本没有试错的时间,让你换…...

Node.js的下载、安装和配置
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
java.util.Properties类介绍
java.util.Properties 是 Java 编程语言中的一个类,用于管理应用程序的配置信息,它继承自 java.util.Hashtable 类,因此它也是基于键值对的数据结构。主要用途是存储应用程序的配置参数,比如数据库连接信息、用户设置等。 以下是 Properties 类的一些主要特点和用法: 存储…...

SpringBoot后端验证码-防止密码爆破功能
一、简介 为了防止网站的用户被通过密码典爆破。引入验证码的功能是十分有必要的。而前端的验证码又仅仅是只防君子不防小人。通过burpsuit等工具很容易就会被绕过。所以后端实现的验证码才是对用户信息安全的一大重要保障。 实现思路: 1.引入图形生成的依赖 2.生成…...
ChatEval:通过多代理辩论提升LLM文本评估质量
论文地址:ChatEval: Towards Better LLM-based Evaluators through Multi-Agent Debate | OpenReviewText evaluation has historically posed significant challenges, often demanding substantial labor and time cost. With the emergence of large language models (LLMs…...
关于美国服务器IP的几个常见问题
在租用美国服务器时,与之密切相关的一个要素就是IP,关于IP的问题总是有人问起,这里列举几项常见的问题,以供参考。 一、IP收费吗? 一般情况下,在租用服务器时,会赠送几个IP,因为这些…...

redis运维:sentinel模式如何查看所有从节点
1. 连接到sentinel redis-cli -h sentinel_host -p sentinel_port如: redis-cli -h {域名} -p 200182. 发现Redis主服务器 连接到哨兵后,我们可以使用SENTINEL get-master-addr-by-name命令来获取当前的Redis主服务器的地址。 SENTINEL get-master-a…...

价格疑云?格行WiFi创始人亲解谜团,性价比之王如何炼成?
随身wifi行业乱象频出,作为行业领跑品牌的格行随身wifi,关于价格问题一直备受质疑。关于设备上的“格行自有格行的骄傲”也被外界认定为是自大,甚至发展的线下一万多家门店也被同行不认可。近日,企业财经专访记者有幸采访了格行随…...

揭秘“消费即赚”的循环购模式
大家好,我是吴军,今天我将带您深入探索一种颠覆传统的新型商业模式——循环购模式。在这个模式中,消费者不仅能享受到购物的乐趣,还能通过消费获得实实在在的回报,甚至实现“边消费边赚钱”的奇妙体验。您是否好奇&…...

javaweb个人主页设计(html+css+js)
目录 1 前言和要求 1.1 前言 1.2 设计要求 2 预览 2.1 主页页面 2.2 个人简介 2.3 个人爱好 2.4 个人成绩有代码,但是图片已省略,可以根据自己情况添加 2.5 收藏夹 3 代码实现 3.1 主页 3.2 个人简介 3.3 个人爱好 3.4 个人成绩ÿ…...

Android常用设计模式(小白必看)
不要担心冗长,3分钟解决面试和学习问题,收藏再看 目的:当作一种模板,结合自身特点,针对项目需求来使用 目录 单例模式 特点: 实现方式: 1、饿汉式 2、线程安全的懒汉式 3、双重校验锁 使…...
swift获取app网络和本地网络权限
请求蓝牙权限: //蓝牙if #available(iOS 13.1, *) {let autostate CBManager.authorizationif(autostate .notDetermined){print("")self.manager CBCentralManager(delegate: nil, queue: DispatchQueue.main,options: [CBCentralManagerOptionShowPo…...

用LangGraph、 Ollama,构建个人的 AI Agent
如果你还记得今年的 Google I/O大会,你肯定注意到了他们今年发布的 Astra,一个人工智能体(AI Agent)。事实上,目前最新的 GPT-4o 也是个 AI Agent。 现在各大科技公司正在投入巨额资金来创建人工智能体(AI …...

ubuntu20.04系统编译yolov8-obb.cpp代码记录
任务内容 在做ncnn-yolov8-obb模型安卓端移植的过程中,对开源代码进行调试。为了确认开源代码yolov8-obb.cpp可以移植开发,先对代码进行复现。因此在linux系统下编译yolov8-obb.cpp代码,验证项目中的代码是可运行的。然后再把这个代码中的模…...
JavaScript的数组与函数
数组 <script type"text/javascript">/** 知识点:数组* 理解:一维数组的容器* 概念:* 1.数组中的数据叫做元素* 2.元素都有编号叫做下标/索引* 3.下标从0开始* 注意:* 1.数组作为数据的容器…...
opencv--把cv::Mat数据转为二进制数据的保存和读取
保存 #include <opencv2/opencv.hpp> #include <iostream> #include <fstream>void saveMatToBinary(const cv::Mat& mat, const std::string& filename) {std::ofstream ofs(filename, std::ios::binary);if (!ofs.is_open()) {std::cerr <<…...

【微信小程序开发实战项目】——个人中心页面的制作
👨💻个人主页:开发者-曼亿点 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 曼亿点 原创 👨💻 收录于专栏:…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...