JavaEE 【知识改变命运】02 多线程(1)
文章目录
- 线程是什么?
- 1.1概念
- 1.1.1 线程是什么?
- 1.1.2 为什么要有线程
- 1.1.3 进程和线程的区别
- 1.1.4 思考:执行一个任务,是不是创建的线程或者越多是不是越好?(比如吃包子比赛)
- 1.1.5 ) Java 的线程 和 操作系统线程 的关系
- 1.2 对多线程程序的理解
- 1.2.1 ) Java 的线程 和 操作系统线程 的关系
- 1.3 创建线程的两种方式
- 1.3.1 继承 Thread 类
- 1.3.2实现Runnable接口
- 1.3.3两者创建方法的对比
- 1.3.4 其他形式创建
- 1.3.4.1 匿名类创建Thread子类对象
- 1.3.4.2匿名内部类创建 Runnable ⼦类对象
- 1.3.4.2 lambda 表达式创建 Runnable ⼦类对象
- 1.4 jconsloe使用
线程是什么?
1.1概念
1.1.1 线程是什么?
- 线程是就是一个执行流,每个执行流之间都可以按照一定顺子执行自己的代码,多个线程可以”同时“执行多分代码
- 举例:进程就像一个程序,比如qq,迅雷,进程是程序的一次执行过程,或者是正在运行的一个程序,是动态的过程有它自己的产生存在和消亡的过程
- 线程是又进程创建的,是进程的一个实体,一个进程可以拥有多个线程,把迅雷比作一个进程,而同时下载多条视频,就是多条线程在工作。
1.1.2 为什么要有线程
- “并发式编成”已经成为了编成界的“刚需”
- 单核 CPU 的发展遇到了瓶颈. 要想提⾼算⼒, 就需要多核 CPU. ⽽并发编程能更充分利⽤多核 CPU资源.
- 有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的⼯作, 也需要⽤到并发编程.
- 重点:进程虽然可以进程并发编成,但是线程比进程更轻量。
解释:进程的创建也需要申请资源,而申请资源对于系统的性能影响比较大。
举个例子:张三要开一个工厂,工业园相当于是操作系统,地皮是固定的,张三的工厂就像一个进程,生产线就像一个线程,张三的工厂是生产皮包的,里面只有一条生产线,现在我们要提高产量,是重新建一个场比较好?,还是在原来的工厂中加一条生产线好呢?,肯定是只增加一条生产线,这样就节省了工业园地皮的面积资源,也利用张三工厂的面积资源,线程的出现更好的利用了系统的资源。
- 其次, 虽然多进程也能实现 并发编程, 但是线程⽐进程更轻量,
创建线程比创建进程更快
销毁线程比销毁进程更快
调度线程比调度进程更快。
- 线程虽然比进程更轻量,但是⼈们还不满⾜, 于是⼜有了 “线程池”(ThreadPool) 和 “协程”(Coroutine)
1.1.3 进程和线程的区别
1.进程里面包含线程:每一个进程里面至少包含一个主线程
2.进程是申请资源的最小单位
3.线程是cpu调度的最小单位
4.进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间 ,所以进程与进程之间互不影响,线程与线程之间可能产生影响
5.一个线程受到影响,会导致进程的结束,⼀个进程挂了⼀般不会影响到其他进程. 但6.是⼀个线程挂了, 可能把同进程内的其他线程⼀起带⾛(整个进程崩溃).
1.1.4 思考:执行一个任务,是不是创建的线程或者越多是不是越好?(比如吃包子比赛)
我们先思考下创造进程的方式:
虽然双进程比单进程确实提升了效率,但是消耗资源太大了,太浪费资源了
我们思考创建线程的方法
效率确实提高了,比进程消耗的资源小
我们再思考一下,根据上面的情况,我们无限创建线程,是不是线程创建的越多越好呢?
答案肯定不是的,这样会出现线程争抢资源问题,如果一个线程崩溃就会造成整个进程的崩溃
其实我们可以根据cpu的逻辑处理器来创建线程
当线程小于逻辑处理器,创建线程会提升效率
当线程大于逻辑处理器,创建线程的线程都是阻塞等待状态,从而没有发挥出线程的效果,创建线程本来就会消耗资源,从而白白消耗资源
- 总结:通过提升线程,我们可以提高效率,但是要根据实际情况来创建,不能盲目创建
1.1.5 ) Java 的线程 和 操作系统线程 的关系
线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对⽤⼾层提供了⼀些 API 供⽤⼾使⽤(例如 Linux 的 pthread 库).Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进⾏了进⼀步的抽象和封装.
1.2 对多线程程序的理解
1.2.1 ) Java 的线程 和 操作系统线程 的关系
- 线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对⽤⼾层提供了⼀些 API 供⽤⼾使⽤(例如 Linux 的 pthread 库).Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进⾏了进⼀步的抽象和封装.
- 线程与普通程序的区别:每个线程都是⼀个独⽴的执⾏流,多个线程之间是 “并发” 执⾏的
import java.util.Random; public class ThreadDemo {private static class MyThread extends Thread {@Overridepublic void run() {Random random = new Random();while (true) {// 打印线程名称System.out.println(Thread.currentThread().getName());try {// 随机停⽌运⾏ 0-9 秒Thread.sleep(random.nextInt(10));} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();Random random = new Random();while (true) {// 打印线程名称System.out.println(Thread.currentThread().getName());try {Thread.sleep(random.nextInt(10));} catch (InterruptedException e) {// 随机停⽌运⾏ 0-9 秒e.printStackTrace();}}} }
我们可以jconsole这个工具查看线程
里面有一个mian主线程,和Thread-0子线程
1.3 创建线程的两种方式
1.3.1 继承 Thread 类
@Override//自定义的线程的执行体,线程执行的代码写在这里public void run(){while (true){System.out.println("hello myThread ");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} } class Main{public static void main(String[] args) {MyThread myThread=new MyThread();//创建一个线程对象myThread.start();//启动线程while (true){System.out.println("hello mainThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
1:PCB是操作系统层面的
2:Thread是java层面的线程。两者是一 一对应的
3:过程:java创建一个线程------jvm调用系统API--------创建系统中线程------参与调度cpu
4. 线程执行的顺序是没有规律的,跟cpu的调度有关,因为cpu是“抢占式”执行,所以那个线程当前占用cpu资源是不能确定的
5.能不能调用run()方法执行线程,答案是不行的,因为run方法是java层面的,是不能启动线程的。
6:
start()开始后,并不意味着线程立马执行,
1.3.2实现Runnable接口
@Overridepublic void run() {while (true){System.out.println("hello myRunnable");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}} class Main{public static void main(String[] args) {MyRunnable myRunnable=new MyRunnable();//创建一个线程任务对象// 创建 Thread 类实例, 调⽤ Thread 的构造⽅法时将 Runnable 对象作为 target 参数.Thread thread=new Thread(myRunnable);//创建一个线程对象,thread.start();//启动线程while (true){System.out.println("hello mainThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} } ```
这种方法实现底层原码过程:
其实这种模式是一种及简化的代理模式,这里模拟实现一下
//模拟实现一个Thread类的代理类,模拟Thread的启动
public class ThreadProxy implements Runnable{private Runnable target;public ThreadProxy(Runnable target) {this.target = target;}@Overridepublic void run(){if (target!=null){target.run();}}public void start(){start0();}private void start0() {run();}}
class Main{public static void main(String[] args) {
// ThreadProxy threadProxy01 = new ThreadProxy(new Runnable() {
// @Override
// public void run() {
// while (true){
// System.out.println("hello myRunnable");
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// });
// threadProxy01.start();Tiger tiger = new Tiger();ThreadProxy threadProxy02 = new ThreadProxy(tiger);threadProxy02.start();}
}
class animal {
}
class Tiger extends animal implements Runnable{public void run(){System.out.println("老虎嗷嗷叫");}
}
1.3.3两者创建方法的对比
- 继承 Thread 类, 直接使⽤ this 就表⽰当前线程对象的引⽤.
- 实现 Runnable 接⼝, this 表⽰的是 MyRunnable 的引⽤. 需要使⽤Thread.currentThread()
- java是单继承模式,在某种情况下一个类可能已经继承某个父类,这时在用来继承Thread类的方法创造线程是显然不可能的
- 实现 Runnable 接⼝,实现了高内聚低耦合的特点,线程和业务逻辑分开,后面修改代码时候,相互影响最小化。
解释:举例一个场景:两条生成皮鞋的生产线,一条生产皮包生产线
1.3.4 其他形式创建
1.3.4.1 匿名类创建Thread子类对象
public class Main {public static void main(String[] args) {Thread t1=new Thread(){@Overridepublic void run() {while (true){System.out.println("hello myThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};t1.start();}}
1.3.4.2匿名内部类创建 Runnable ⼦类对象
public class Main {public static void main(String[] args) {Thread t2=new Thread(new Runnable(){@Overridepublic void run() {while (true){System.out.println("hello myRunnable");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}});t2.start();}
}
1.3.4.2 lambda 表达式创建 Runnable ⼦类对象
public class Main {public static void main(String[] args) {Thread t3=new Thread(()->{while (true){System.out.println("hello myLambda");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t3.start();}}
1.4 jconsloe使用
我们这里重提一下,先调用的方法会先入栈,后调用的后入栈,后调用的方法执行完后就会出栈。
相关文章:

JavaEE 【知识改变命运】02 多线程(1)
文章目录 线程是什么?1.1概念1.1.1 线程是什么?1.1.2 为什么要有线程1.1.3 进程和线程的区别1.1.4 思考:执行一个任务,是不是创建的线程或者越多是不是越好?(比如吃包子比赛)1.1.5 ) Java 的线程…...

Pytorch使用手册-Transforms(专题四)
Transforms(变换) 在 PyTorch 数据处理中的重要性和使用方法,特别是如何通过 torchvision.transforms 模块对数据进行预处理和变换,使其适合用于训练机器学习模型。以下是具体的内容解读: 什么是 Transforms? 数据通常在收集后并非直接适合用于训练机器学习模型,需要通…...

【Android】ARouter的使用及源码解析
文章目录 简介介绍作用 原理关系 使用添加依赖和配置初始化SDK添加注解在目标界面跳转界面不带参跳转界面含参处理返回结果 源码基本流程getInstance()build()navigation()_navigation()Warehouse ARouter初始化init帮助类根帮助类组帮助类 completion 总结 简介 介绍 ARouter…...

ValueError: bbox_params must be specified for bbox transformations
错误 ValueError: bbox_params must be specified for bbox transformations 是因为使用了需要处理边界框(bboxes)的增强操作,但在 albumentations.Compose 中没有正确设置bbox_params 参数。 bbox_params 是用来指定如何处理边界框的配置。…...

挂壁式空气净化器哪个品牌的质量好?排名top3优秀产品测评分析
随着挂壁式空气净化器市场的不断扩大,各类品牌与型号琳琅满目。但遗憾的是,一些跨界网红品牌过于追求短期效益,导致产品在净化效果与去除异味方面表现平平,使用体验不佳,甚至可能带来二次污染风险,影响人体…...

钉钉数据如何高效集成到金蝶云星空系统
钉钉数据集成到金蝶云星空的技术案例分享 在企业日常运营中,办公用品采购流程的高效管理至关重要。为了实现这一目标,我们采用了轻易云数据集成平台,将钉钉中的采购申请单数据无缝对接到金蝶云星空系统中。本次案例将详细解析【办公用品采购…...

躺平成长-腾讯云数据库(又消失了一次)
开源竞争: 当你无法彻底掌握技术的时候,你就开源这个技术,形成更多的技术依赖,你会说 这不就是在砸罐子吗?一个行业里面总会有人砸罐子的,你不如先砸罐子,还能听个响声。 数据库的里面清洁的数据…...

初学 flutter 问题记录
windows搭建flutter运行环境 一、运行 flutter doctor遇到的问题 Xcmdline-tools component is missingRun path/to/sdkmanager --install "cmdline-tools;latest"See https://developer.android.com/studio/command-line for more details.1)cmdline-to…...

Hadoop的MapReduce详解
文章目录 Hadoop的MapReduce详解一、引言二、MapReduce的核心概念1、Map阶段1.1、Map函数的实现 2、Reduce阶段2.1、Reduce函数的实现 三、MapReduce的执行流程四、MapReduce的使用实例Word Count示例1. Mapper类2. Reducer类3. 执行Word Count 五、总结 Hadoop的MapReduce详解…...

全新配置ubuntu18.04深度学习环境
1、下载显卡驱动 1.1、驱动下载 连接:显卡驱动 手动驱动搜索-》查找-》查看-》下载 下载可使用指令 wget https://us.download.nvidia.com/XFree86/Linux-x86_64/535.216.01/NVIDIA-Linux-x86_64-535.216.01.run 2、下载安装cuda12.0 wget https://developer.do…...

持续集成与持续部署:CI/CD实现教程
以下是一个基于常见工具实现 CI/CD 的基本教程示例,这里以 Git、Jenkins、Maven(用于 Java 项目构建和管理依赖,其他语言项目可替换为对应构建工具)以及 Docker(用于容器化部署,非必需但很常用)…...

深度学习实验十二 卷积神经网络(3)——基于残差网络实现手写体数字识别实验
目录 一、模型构建 1.1残差单元 1.2 残差网络的整体结构 二、统计模型的参数量和计算量 三、数据预处理 四、没有残差连接的ResNet18 五、带残差连接的ResNet18 附:完整的可运行代码 实验大体步骤: 先前说明: 上次LeNet实验用到的那…...

Linux系统如何排查端口占用
如何在Linux系统中排查端口占用 在Linux系统中,当您遇到网络服务无法启动或响应异常的情况时,可能是因为某个特定的端口已经被其他进程占用。这时,您需要进行端口占用情况的排查来解决问题。本文将介绍几种常用的命令行工具和方法࿰…...

Linux常用命令之id命令详解
id命令详解 id 命令在 Linux 和 Unix 系统中用于显示用户的标识信息,包括用户ID(UID)、组ID(GID)以及用户所属的附加组。这个命令对于系统管理员和开发者来说非常有用,因为它能帮助他们确认运行命令或脚本…...

WGCLOUD如何部署在ARM平台
WGCLOUD是一款开源免费的运维平台,非常强大方便,可以帮我们提高运维效率 我们项目中,大部分是ARM的服务器,那么如何部署WGCLOUD呢,其实挺简单的 首先是部署服务端server 我们只要安装好对应ARM版本的JDK,…...

K8S + Jenkins 做CICD
前言 这里会做整体CICD的思路和流程的介绍,会给出核心的Jenkins pipeline脚本,最后会演示一下 实验/实操 结果 由于整体内容较多,所以不打算在这里做每一步的详细演示 - 本文仅作自己的实操记录和日后回顾用 要看保姆式教学的可以划走了&…...

HarmonyOS4+NEXT星河版入门与项目实战(11)------Button组件
文章目录 1、控件图解2、案例实现1、代码实现2、代码解释3、运行效果4、总结1、控件图解 这里我们用一张完整的图来汇整 Button 的用法格式、属性和事件,如下所示: 按钮默认类型就是胶囊类型。 2、案例实现 这里我们实现一个根据放大和缩小按钮来改变图片大小的功能。 功…...

小米note pro一代(leo)线刷、twrp、magisk、TODO: android源码编译
本文主要说android5 整体思路 android 5.1 twrp magisk Zygisk(Riru) Dreamland(xposed) Riru不支持android5.1, 因此只能选择Zygisk : 如果你正在使用 Android 5,你必须使用 Zygisk 因为 Riru 并不支持 Android 5. 基于magisk之上的xposed 其中提到的 作者…...

鸿蒙开发Hvigor插件动态生成代码
Hvigor允许开发者实现自己的插件,开发者可以定义自己的构建逻辑,并与他人共享。Hvigor主要提供了两种方式来实现插件:基于hvigorfile脚本开发插件、基于typescript项目开发。下面以基于hvigorfile脚本开发插件进行介绍。 基于hvigorfile脚本…...

使用ENSP实现静态路由
一、双路由器静态路由 1.项目拓扑 2.项目实现 (1)路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为1.1.1.1/24 ip address 1.1.1.1 24进入g0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置为192.168.1.1/24 ip ad…...

Java String 字符串常用操作
一、Java String 字符串常用操作 1、替换 Java字符模板替换 public static final String temp"private {0} {1};";public static void main(String[] args) {System.out.println(MessageFormat.format(temp,"String","str"));} replaceAll替换…...

4.4 MySQL 触发器(Trigger)
触发器是一种特殊的数据库对象,在特定事件(如INSERT、UPDATE或DELETE)触发时自动执行定义好的操作。它可以帮助我们实现更高效的数据管理和业务规则的约束。 1. 简介 1.1 什么是触发器 触发器(Trigger)是由用户定义的…...

C语言——break、continue、goto
目录 一、break 二、continue 1、在while循环中 2、在for循环中 三、go to 一、break 作用是终止循环,在循环内遇到break直接就跳出循环。 注: 一个break语句只能跳出一层循环。 代码演示: #include<stdio.h>void test01() {for (…...

oracle数据恢复总结篇
前言:数据恢复的关键 定删除时间点:首先,需要知道是什么时间进行的删除操作。 如果不能确定具体时间点,可以选择尽量准确的删除数据前的时间。 oracle数据库如果使用drop指令误删除了数据应该如何恢复呢? 如果没有进行其他操作&…...

运维面试题.云计算面试题之四.K8S
常见的k8s运维面试题 1、简述ETCD及其特点? etcd是一个用于配置共享和服务发现的键值存储系统,能够为整个分布式集群存储关键数据,协助集群正常运转 服务端将配置信息存储在etcd中,客户端从etcd中得到配置信息,etcd监听配置信息的变化,发现配置变化通知到客户端 特点 - 安…...

el-select 和el-tree二次封装
前言 本文章是本人在开发过程中,遇到使用树形数据,动态单选或多选的需求,element中没有这种组件,故自己封装一个,欢迎多多指教 开发环境:element-UI、vue2 组件效果 单选 多选 组件引用 <treeselec…...

C++11:多线程编程
目录 线程库基本用法创建线程给线程传递参数线程分离 常见数据未定义错误传递指针或引用指向局部变量的问题传递指针或引用指向已释放的内存的问题类成员函数作为入口函数,类对象被提前释放智能指针来解决该问题入口函数为类的私有成员函数 互斥量死锁 lock_guard与…...

【H2O2|全栈】JS进阶知识(八)ES6(4)
目录 前言 开篇语 准备工作 浅拷贝和深拷贝 浅拷贝 概念 常见方法 弊端 案例 深拷贝 概念 常见方法 弊端 逐层拷贝 原型 构造函数 概念 形式 成员 弊端 显式原型和隐式原型 概念 形式 constructor 概念 形式 原型链 概念 形式 结束语 前言 开篇语…...

OmniDiskSweeper :一款专为 macOS 设计的磁盘使用分析工具
OmniDiskSweeper 是一款专为 macOS 设计的磁盘使用分析工具,由 The Omni Group 开发。它的主要目的是帮助用户可视化磁盘上的文件和文件夹,并找出占用大量空间的文件,从而帮助用户释放磁盘空间。 OmniDiskSweeper 的特点包括: 简…...

【什么是Redis?】
Redis:高性能内存数据库的深度探索 在当今这个数据驱动的世界里,数据库的选择直接关系到应用程序的性能、可扩展性和可靠性。在众多数据库解决方案中,Redis以其卓越的性能、丰富的数据结构和灵活的使用场景脱颖而出,成为众多开发…...