【JavaEE初阶】认识线程(Thread)
目录
🌾 前言
🌾 了解线程
🌈1.1 线程是什么?
🌈1.2 一些基本问题
🌾2、创建线程的方式
🌈 2.1 继承Thread类
🌈 2.2 实现Runnable接口并重写run()方法
🌈 注意:多个线程的写法
🌾3、多线程编程的意义
🌾4、线程的类与常用方法
🌈 4.1 构造方法
🌈 4.2 Thread类的几个常见属性
🌾5、线程的状态
🌾 前言
在学习之前,我们先简单的了解一下计算机中的常见的概念。
1、冯诺依曼结构体系
现代的计算机大多遵循冯诺依曼体系结构。主要由运算器,控制器,存储器,输入设备,输出设备组成。
2、操作系统
操作系统是一组做计算机资源管理系统的统称。常见的操作系统由Windows系列,Linux系列,OSX系列,ISO系列,Android系列。操作系统的作用主要有:(1)向上为应用程序提供一个稳定的运行环境;(2)向下管理所有的硬件设备;(3)为用户提供一个人机交互的界面。
3、进程
每一个运行起来的程序(软件),操作系统都会以进程的形式将他们管理起来。在操作系统中,每一个进程被描述为一个PCB(进程控制块抽象)。一个PCB中主要包括:PID,内存指针,文件描述符表,进程的优先级,进程的状态,上下文信息和记账信息。
CPU分配 -> 进程调度:假设大部分场景下都是单CPU单核的计算机。操作系统对于CPU资源的分配,采用的是时间模式:不同的进程在不同的时间段去使用CPU资源。
内存分配 ->内存管理:操作系统对内存资源的分配,采用的是空间模式:不同的进程使用内存中的不同区域,互相之间不会干扰。
4、虚拟内存空间
进程启动之后会申请内存空间,正常情况下是没有问题的。但是可能会出现一些特殊情况,比如C++中的野指针等。因此实际中,操作系统中有一个模块叫做MMU,MMU会给每个进程分配一个虚拟内存地址,这个地址和真实的物理内存之间建立映射关系。当进程越界访问内存空间时,MMU直接会进行拦截,起到了一个校验的作用,不会对真实的物理内存造成影响。
存在的问题:但是由于MMU的限制,导致不同进程之间不能够互相访问内存,所以如何实现进程之间的数据共享,从而达到“信息交换”的需求?针对这一问题,进程间通信的需求应运而生。目前,主流操作系统提供的进程通信机制主要有:管道,共享内存,文件,网络,信号量,信号。
问题:并发与并行的区别?
在一个处理器上不停横向的轮动叫做并发,在多个处理器上执行叫做并行。通俗解释就是:并发是:一会干这件事,一会干那件事,但其实同一时刻只能干一件事;并行是:一边干这件事,一边干那件事,在同一时刻干多件事,真正意义上的同时进行,在编程方面,我们统一称为并发编程。
🌾 了解线程
🌈1.1 线程是什么?
一般多进程用来处理一个很大或者很复杂的任务。当进程启动的时候,需要申请内存,申请文件资源,将PCB加入到链表中;当进程结束的时候,需要释放文件,释放内存,从链表中删除PCB。但是在这个过程中申请和释放资源的操作是十分耗时的。因此为了解决资源消耗的问题,提出了一个轻量级进程的概念(线程)。在创建线程的时候使用的是进程创建时申请到的所有资源,线程只需要关注要处理的任务即可。
举个例子:比如张三设计了一些皮包,他要去开一个工厂。他需要做以下一些事情:、
(1)去工业园区申请地皮,水电,仓库等(花了一个月的时间和几十万的钱);
(2)修建厂房和基础设施(花了几个月和几十万的钱);
(3)购买生产设备和原材料,招工(花了一周和几万块钱);
(4)开始生产。
主要关注两者之间的对应关系!
🌈1.2 一些基本问题
❓ 问题1:进程与线程之间的区别?(面试题)
(1)对于一个进程而言,必然会有一个线程(主线程);
(2)进程是申请系统资源的最小单位,线程是CPU调度的最小单位;
(3)进程之间互不影响,线程使用的是进程统一申请来的资源,线程之间可以相互影响。
❓ 问题2: 使用多线程编程的原因?
(1)为了充分利用CPU的资源
(2)利用轻量级进程的特性来减少系统性能的开销:
线程创建的效率比进程高;
线程销毁的效率比进程高;
线程调度的效率比进程高
❓ 问题3:使用多线程存在的问题?
当线程数量增大到一定程度之后,可能会给CPU调度带来负担,出现资源抢夺的问题,就会出现一些线程不安全的现象。
🌾2、创建线程的方式
🌈 2.1 继承Thread类
三部曲:继承Thread来创建一个线程类 -> 创建MyThread的实例 -> 使用start()方法启动线程
(1)正常写法
public class Demo1_createThread {public static void main(String[] args) {Thread t = new MyThread();t.start();while (true){System.out.println("main thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
class MyThread extends Thread{@Overridepublic void run() {while (true){System.out.println("这里是线程运行的代码");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
(2)使用匿名内部类的写法
public static void main(String[] args) {//匿名内部类的形式Thread t = new Thread(){@Overridepublic void run() {while (true){System.out.println("生产生产生产...金币金币金币...+1+1+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};//启动进程t.start();}
🌈 2.2 实现Runnable接口并重写run()方法
三部曲:实现Runnable接口 -> 创建Thread类实例,将Runnable对象作为其目标参数 -> 使用start()方法启动线程
注意:在调用start()方法后,JVM会调用系统API,并在系统中生成一个PCB来执行run()方法中的代码。
(1)正常写法
public class Demo2_createRunnable {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t = new Thread(myRunnable);t.start();while (true){System.out.println("main thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
class MyRunnable implements Runnable{@Overridepublic void run() {while (true){System.out.println("这是线程运行的代码");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
注意:两个线程并不是有序的交替运行,因为CPU的调度是随机的。线程的执行是“抢占式执行”。
(2)使用匿名内部类的写法
public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while (true){System.out.println("生产皮包,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});//开启线程t.start();}
(3)使用Lambda写法
public static void main(String[] args) {//Lambda表达式的使用条件就是该接口必须是一个函数式接口//比如Runnable接口就是一个 FunctionalInterface:所谓的函数式接口就是里面只有一个方法。比如(Runnable接口)中只有一个run();//怎么用Lambda表达式呢?()里写run方法的所有参数名,不需要参数类型,然后一个->即可。后面是正常的函数的功能实现Thread t = new Thread(()->{while (true){System.out.println("生产皮包,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//开启线程t.start();}
❓ 问题:使用Runnable 定义任务的好处?
(1)解耦,将定义线程与定义任务分开。(其中解耦的意思就是将不同的功能都给分开,如果要修改或者查找相应的功能的时候可以在指定的位置找)
(2)将创建线程与定义任务分开,以便修改代码时,可以统一修改。
🌈 注意:多个线程的写法
public class Demo3_multiRunnable {public static void main(String[] args) {//创建任务的对象MyRunnable1 myrunnable1 = new MyRunnable1();MyRunnable2 myrunnable2 = new MyRunnable2();//创建生产皮包的线程Thread t1 = new Thread(myrunnable1);Thread t2 = new Thread(myrunnable1);//创建生产皮鞋的线程Thread t3 = new Thread(myrunnable2);//启动线程t1.start();t2.start();t3.start();}
}
//描述生产皮包的任务
class MyRunnable1 implements Runnable{@Overridepublic void run() {System.out.println("生产皮包,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
//描述生产皮鞋的任务
class MyRunnable2 implements Runnable{@Overridepublic void run() {System.out.println("生产皮鞋,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
🌾3、多线程编程的意义
使用多线程编程主要是为了充分利用CPU资源,提高程序的运行效率。
🌰:现在我们分别对两个变量进行10亿次的自增,分别使用两种方式:串行和并行。观察一下它们之间的时间差异。理论上来讲,并行应该是串行时间的一半。接下来我们俩看一下实际上是不是这样~
结论:从上可以看出并行时间确实小于串行时间,但并不是严格意义上的一半,这主要是因为每创建一个线程都是要消耗时间和资源的。同样的,我们将计算量变小一些,可以看到反而串行时间小于并行时间。因此我们要知道并不是所有的场景下使用多线程第一可以提升效率,具体是否需要使用多线程主要根据计算量来决定。
🌾4、线程的类与常用方法
🌈 4.1 构造方法
Thread类是JVM用来管理线程的一个类。
🌈 4.2 Thread类的几个常见属性
(1) 获取线程名:Thread.currentThread().getName();
(2)是否后台线程:isDaemon()
isDaemon() 默认为false(前台线程),如果要创建后台线程则传入true,手动设置为后台线程。其中在main方法结束之后,线程会自动结束。
❓ 问题:前台线程与后台线程的区别?
应用程度的主线程以及使用new Thread方式构造的线程都默认是前台线程。通过BeginXXX方法运行的线程都是后台线程,托管线程池中的线程都是后台线程。
前台线程与后台线程的主要区别就是:进程会等待所有的前台线程完成后再结束工作,但是如果只剩下后台线程,则会直接结束工作。如果程序定义了一个不会完成的前台线程,主程序不会正常结束。
比如银行转账的业务,一定要用前台线程;统计微信步数这种处理容错率比较高的业务或者辅助功能等,就可以使用后台线程。
后台线程演示:
public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//第一次:在线程启动之前 设置线程为后台,观察线程的存活状态thread.setDaemon(true);System.out.println("在线程start之前设置为后台线程,此时的存活状态是:"+ thread.isAlive());//启动线程thread.start();//此时休眠是因为start之后,系统要去创建PCB,给系统一点时间能够创建成功Thread.sleep(2000);//第二次:在start线程之后,观察线程的存活状态System.out.println("在线程start之后观察线程的存活状态:"+thread.isAlive());System.out.println("main线程执行完成");System.out.println("此时线程是否存活:"+thread.isAlive());}
(3)是否存活 isAlive()指的是系统的线程PCB是否存活,并不是说我们new出来的Thread对象。
(4)是否被中断:停止或者终止当前现成的任务
方式1:通过设置中断标识:主要注意代码中的while(!isQuit) 和 isQuit = true这两点。
方式2:通过调用Thread类提供的interruped()方法来中断线程。isInterrupted()默认为false不中断。
注意看下面的写法:有两处改动,但是会抛出异常。
这主要是因为上面的两处改动都针对的是runnable状态中的异常处理,所以我们还要对 Sleep状态做处理:在catch中处理:有三种方式:
(5)等待一个线程 join():等待线程结束
(6)获取当前线程引用:Thread thread = Thread.currentThread();
(7)start()方法
❓ 问题:start()方法与run()方法的区别?(面试题)
start():申请一个真正的系统线程run() :定义线程要执行的任务。
直接调用run方法,并不会去申请一个真正的系统线程(PCB),只是一个普通的方法调用,是单独的调用对象的方法。调用start方法,JVM会调用本地方法去系统中真正的申请一个线程(PCB),并执行run方法中 的逻辑。
🌾5、线程的状态
注意:线程的状态指的是Thread对象(有自己的生命周期)的状态,并不是PCB的状态。主要有以下几种:
1、NEW :java对象创建好了,但是还没有调用start方法创建PCB。
2、RUNNABLE : 就绪和运行状态。可以随时调度到CPU中执行。
3、TERMINATED: 线程任务执行完成,PCB在操作系统中已经销毁,但是java对象还存在。
4、TIMED_WATING :等待一段时间,这个时间是有时间限制的等待(过时不候)。比如sleep(),常见的访问超时。
5、WAITING:没有时间限制的等待。
6、BLOCK:等待锁的时候进入的阻塞状态。
最后,知道 在系统中针对线程的两个调度是用两个队列来实现的。准备执行的线程在就绪队列中,随时等待CPU调度。当调用sleep,wait,join方法时,就会被移动到阻塞队列中。当休眠时间到了之后,就会被移动回就绪队列,重新参与CPU调度。
相关文章:

【JavaEE初阶】认识线程(Thread)
目录 🌾 前言 🌾 了解线程 🌈1.1 线程是什么? 🌈1.2 一些基本问题 🌾2、创建线程的方式 🌈 2.1 继承Thread类 🌈 2.2 实现Runnable接口并重写run()方法 🌈 注意…...

自动化运维工具一Ansible Roles实战
目录 一、Ansible Roles概述 1.1.roles官方的目录结构 1.2.Ansible Roles依赖关系 二、Ansible Roles案例实战 2.1.Ansible Roles NFS服务 2.2 Roles Memcached 2.3 Roles-rsync服务 一、Ansible Roles概述 之前介绍了 Playbook 的使用方法,对于批量任务的部…...
json 中有递归parentId节点转 c#实体类时如何处理
如果您有一个具有递归parentId节点的JSON数据,并且您需要将其转换为C#实体类,则可以使用以下方法: 创建一个类来表示JSON对象的节点,包括它的属性和子节点。 public class Node {public int Id { get; set; }public string Name …...

给大家介绍几个手机冷门但好用的小技巧
技巧一:拍照识别植物 手机的拍照识别植物功能是指在使用手机相机时,可以通过对植物进行拍照,并通过植物识别技术,获取植物的相关信息和资料。其主要优点如下: 方便实用:使用拍照识别植物功能,…...

2.3 定点乘法运算
学习目标: 如果我要学习定点乘法运算,我会按照以下步骤进行学习: 确定学习目标:明确学习定点乘法运算的目的和重点,以便有针对性地进行学习。 掌握基础知识:首先需要了解定点数和定点乘法的基础知识&…...

C++每日一练:打家劫室(详解动态规划法)
文章目录 前言一、题目二、分析三、代码总结 前言 这题目出得很有意思哈,打劫也是很有技术含量滴!不会点算法打劫这么粗暴的工作都干不好。 提示:以下是本篇文章正文内容,下面案例可供参考 一、题目 题目名称: 打家…...
Wireshark使用
Capture Filters 语法 <Protocol name><Direction><Hosts><Value><Logical operations><Expressions> e.g 1.tcp src port 443 只抓取来源端口是443的tcp数据 2.not arp 不获取arp数据 3.port 80 获取端口是80的数据,不指…...

这才是 SpringBoot 统一登录鉴权、异常处理、数据格式 的正确姿势
本篇将要学习 Spring Boot 统一功能处理模块,这也是 AOP 的实战环节 用户登录权限的校验实现接口 HandlerInterceptor WebMvcConfigurer 异常处理使用注解 RestControllerAdvice ExceptionHandler 数据格式返回使用注解 ControllerAdvice 并且实现接口 Response…...

Java面试题总结 | Java面试题总结6-MYSQL模块(持续更新)
Mysql 文章目录 Mysql关系型数据库和非关系型数据库的区别什么是ORM?-**mybatis**如何评估一个索引创建的是否合理?Count函数执行效果上:执行效率上:count(主键)和count(列名) 数据库的三大范式Mysql中char和varchar的区别数据库设计或者功能…...
Linux命令集(Linux文件管理命令--mv指令篇)
Linux命令集(Linux文件管理命令--mv指令篇) Linux文件管理命令集(mv指令篇)2. mv(move)1. 文件移动2. 递归移动目录3. 文件目录重命名4. 强制移动5. 备份覆盖的目标文件6. 试探性移动7. 显示移动进度8. 补集操作9. 修改文件的权限…...
不一样的 Git 之间 | GitLab vs GitHub vs Gitee vs GitCode
Git仓库对比:GitLab vs GitHub vs Gitee vs GitCode 在软件开发中,版本控制是必不可少的工具之一。Git作为目前最为流行的版本控制系统,也逐渐成为了开发者们的标配。但是,如何选择一个合适的Git仓库来存储您的代码呢?…...

海尔牵头IEEE P2786国际标准通过Sponsor投票并连任工作组主席
01 海尔牵头IEEE P2786国际标准 通过Sponsor投票 并连任工作组主席 海尔牵头制定的全球首个服装物联网国际标准IEEE P2786《Standard for General Requirements and Interoperability for Internet of Clothing》通过Sponsor投票,标志着该国际标准草案得到了行业…...

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析
倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析 倾斜摄影超大场景的三维模型的顶层合并需要对纹理进行压缩和抽稀处理,以减小数据量和提高数据的传输和展示性能。以下是一种常用的纹理压缩和抽稀处理技术: 1、纹理图集 纹理瓦片化…...
linux命令之iostat详解
iostat 监视系统输入输出设备和CPU的使用情况 推荐Linux命令在线工具:linux在线查询工具 补充说明 iostat命令 被用于监视系统输入输出设备和CPU的使用情况。它的特点是汇报磁盘活动统计情况,同时也会汇报出CPU使用情况。同vmstat一样,ios…...

【C++】程序员必备知识:认识类与对象
【C】程序员必备知识:认识类与对象 ①.面向过程和面向对象②.类的引入③.类的定义Ⅰ.定义方式Ⅱ.命名规则建议: ④.类的访问限定符及封装Ⅰ.访问限定符Ⅱ.封装 ⑤.类的作用域⑥.类的实例化⑦.类的对象大小计算Ⅰ.如何计算?Ⅱ.类对象存储方式Ⅲ…...

python基础实战5-python基本结构
1 if语句 if语句是用来进行判断的,其使用格式如下 if 要判断的条件: 条件成立时,要做的事情 案例一: age 30 print("------if判断开始------") if age > 18:print("我成年了") print("------if判断…...

移动端异构运算技术 - GPU OpenCL 编程(基础篇)
一、前言 随着移动端芯片性能的不断提升,在移动端上实时进行计算机图形学、深度学习模型推理等计算密集型任务不再是一个奢望。在移动端设备上,GPU 凭借其优秀的浮点运算性能,以及良好的 API 兼容性,成为移动端异构计算中非常重要…...
QString类方法和变量简介(全)
QString类方法和变量简介 操作字符串(|append|insert|sprintf|QString::arg()|prepend|replace|trimmed|simplified)查询字符串(startsWith|endsWith|contains|localeAwareCompare|compare)字符串转换 标准C提供了两种字符串:一种是C语言风格的以"\0"字符…...

中移链控制台对接4A平台功能验证介绍
中移链控制台具备单独的注册登录页面,用户可通过页面注册或者用户管理功能模块进行添加用户,通过个人中心功能模块进行用户信息的修改和密码修改等操作,因业务要求,需要对中移链控制台的用户账号进行集中管理,统一由 4…...

必知的Facebook广告兴趣定位技巧,更准确地找到目标受众
在Facebook广告投放中,兴趣定位是非常重要的一环。兴趣定位不仅可以帮助我们找到我们想要的目标受众,还可以帮助我们避免一些常见的坑。今天,就让我们一起来看看必知的Facebook广告兴趣定位技巧,更准确地找到目标受众。 1.不要只关…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...