当前位置: 首页 > news >正文

JavaEE——何为线程及创建线程

文章目录

  • 一、认识线程
    • 1. 线程的概念
    • 2. 出现多线程的原因
    • 3. 进程与线程
    • 4. 对多线程的详细解释
  • 二、初次实现多线程代码
    • 1. 初步了解
    • 2. 使用 Java 中的工具查看当前的所有线程
    • 3. Java 中创建线程的多种方式

一、认识线程

1. 线程的概念

所谓线程,就是指在一个 ‘执行流’ 中多个线程之间都可以按照自己的顺序执行代码,多个线程之间可以 ‘同时’ 执行多个代码。

2. 出现多线程的原因

首先,并发编程成为了刚需。

  • 随着科技的发展,目前 CPU 的核心已近难以在进行缩小,想要得到更高的算力 “多核” CPU 成为了一种可行的解决方案,因此,并发编程来利用 CPU 资源的操作应运而生。
  • 有些任务操作中需要等待 “IO”,为了让等待的时间不被浪费,此时多线程的优势就体现了出来。

其次,虽然 多进程 也可以实现 并发编程,但是,线程 比 进程 更加轻量

注: 所谓轻量,就是在解决并发编程的前提下,让创建,销毁,调度的速度更快一些。

线程为啥更轻,就是将 申请资源&释放资源 的操作省去了! 下面我给大家简单举一个生活中的例子来解释一下。

  • 我们先设想一个物流的中转站,如图:

在这里插入图片描述
这里就类似于一个进程在执行相关操作。

  • 此时,因为某些原因,运输到我们中转站管辖范围的货物突然增多,为了更好的对快递进行配送,我们就必须要扩建。

无需多虑,这里会有两种操作可供我们选择。

  1. 操作一:重新在城市中找一块地方,建立一个新仓库用来缓解物流压力。

在这里插入图片描述
如图,就是将原来的模式完全复制一份。相当于 多进程 方案

  1. 操作二:将原来的厂房进行整理,在其中新建一个仓库即可。

在这里插入图片描述
这里不难发现,第二种方案,显然比第一种方案成本要小很多,场地和快递分配体系都是可以套用之前的。

这就是 多线程 版本的方案,此时,只要在第一次申请资源时,合理申请,之后增加的操作只需要复用第一次的申请的资源即可,不需要在进行资源的申请等操作…

3. 进程与线程

线程和进程的关系:进程 包含 线程
一个进程中至少包含一个线程,一个进程可以包含多个线程。

进程和线程的关系图表,如下所示:
在这里插入图片描述
我们可以清晰地观察到,同一个进程中的多线程,共用着同一份资源(主要指内存,文字描述符表)

注:

  • 进程是系统 资源分配 的最小单位,线程是系统 调度 的最小单位
  • 一个 线程 是通过一个 PCB 来描述,即,PCB中的状态,上下文,优先级,记账信息等,每一个 线程 都是独立拥有的。
  • 同一个进程多个线程 中 PCB 之间,他们的 pid 是相同的,即,内存指针和文件描述符表是相同的。

4. 对多线程的详细解释

对于多线程的解释,在这里我们依然可以用一个比较有趣的例子来解释。

  • 首先,我们可以设想一个华强劈瓜的情景。

在这里插入图片描述
现在我们知道,要想让华强更好的,更快的进行劈瓜,就需要让华强分身到一个房间中一块劈(即,多线程)。

  • 此时,我们让华强老铁造出更多分身出现在房间中,呢么劈瓜效率就一定会很快吗? 如图:
    在这里插入图片描述
    其实不难发现,华强老铁的增多并不能无限的加快劈瓜的速度。
  1. 桌子周围的空间是有限的 (即,CPU 上的核心数量是有限的)。

  2. 华强老铁太多,最终会出现相互推嚷的情况,让正在用力劈瓜的华强劈歪来。也就是说线程数量太多,核心数量有限,使得大量的时间花费在了线程调度上了

  • 在多线程的条件下,如果某两个华强老铁,一眼看上了同一个瓜,争抢着去劈,此时就可能会打架。

在这里插入图片描述
这种情况在 多进程 中就不会出现,因为多进程是将瓜分配到单独的房间,由一个华强老铁来劈的。
因此,这里就引出了一个线程安全问题

  • 多线程下还会有一个问题
    在这里插入图片描述
    两个华强同时看上一个瓜,1号华强率先下手劈了瓜,2号华强很生气,直接就把瓜摊子掀了,大家都劈不了了。也就是说,如果一个线程出现了问题,如果没有处理好,呢么就有可能导致整个进程崩溃,其他线程也就被迫停止了!

二、初次实现多线程代码

1. 初步了解

首先,我们要知道在 Java 中要实现多线程的一个关键的 Thread 类。
这里,我先展示一段代码,之后再进行详细的解释。

class MyThread extends Thread{//重写线程类中的 run 方法public void run(){while(true){System.out.println("hello thread");//为了让执行变慢加一个 sleeptry {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class ThreadDemo {public static void main(String[] args) {Thread t = new MyThread();//一个线程的创建t.start();//main 方法中主线程的代码实现while(true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

在这里插入图片描述
此处的 start 就只是创建了一个新的线程,注意,start 没有调用 run 方法。

这里创建新线程就是调用操作系统的 API ,通过操作系统内核创建出此线程的 PCB,并且将要执行的指令传递给这个 PCB,当 PCB 被调度到 CPU 上时,就会执行到其中的 run 方法中。
简单来讲,就是 main 方法中的 start 创建新线程,新线程内调用 run 方法。

  • start 和 run 方法之间的区别
    start是真正的从系统资源里创建的独立的执行流。
    run 方法只是描述了线程中需要干的工作。(在,main 方法中调用 run 此时,没有创建任何线程,只有 main 线程在进行工作)

代码执行结果:

在这里插入图片描述
注:这里只是部分结果截取。

在上述的结果中,我们不难看出,两个线程之间执行的先后顺序似乎并不固定,这里就需要提到操作系统调用线程时的方式——抢占式调用。

因此,哪个进程线上,那个进程后上,完全是取决于操作系统调度器的具体实现策略。

2. 使用 Java 中的工具查看当前的所有线程

(1)在安装 jdk 的 bin 目录下,找到上图中的 jconsole 程序。

如图所示:
在这里插入图片描述
(2)运行多个线程的代码的同时,打开程序。

在这里插入图片描述

(3)选择自己的线程后连接,之后点击线程,左下角就会出现如下图的情况。

在这里插入图片描述

3. Java 中创建线程的多种方式

  • 继承 Tread 重写 run 方法。
class MyThread extends Thread{//重写线程类中的 run 方法public void run(){while(true){System.out.println("hello thread");//为了让执行变慢加一个 sleep}}
}public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();//start 表明创建一个线程,新线程t.start();while(true){System.out.println("hello main");}}
}
  • 实现 Runnable 接口
// Runnable 作用,是描述一个“要执行的任务”,run方法就是任务执行的细节
class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("hello thread");}
}public class ThreadDemo2 {public static void main(String[] args) {//这只是描述了个任务Runnable runnable = new MyRunnable();//把任务交给线程执行Thread t = new Thread(runnable);t.start();}
}
  • 使用 匿名内部类 来继承 Thread 方法。
//使用匿名内部类来实现线程的创建
public class ThreadDemo3 {public static void main(String[] args) {//这里创建了 Thread 的子类,但是子类没有名称//但是创建了子类的实例,让 t 指向了该实例,并重写了其中的 run 方法。Thread t = new Thread(){public void run(){System.out.println("hello");}};t.start();}
}
  • 使用 匿名内部类 实现 Runnable

这里的匿名内部类不需要再进行解释

public class ThreadDemo4 {public static void main(String[] args) {//这里与第二种方法极为相似,是直接将 runnable 实例化后传递给匿名内部类Thread t = new Thread(new Runnable(){@Overridepublic void run() {System.out.println("hello");}});t.start();}
}
  • 使用 Lambad 表达式
// lambda 表达式
public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello");});t.start();}
}

到此, 文章结束, 如有不足, 欢迎提出. 如有错误, 欢迎指正!

相关文章:

JavaEE——何为线程及创建线程

文章目录一、认识线程1. 线程的概念2. 出现多线程的原因3. 进程与线程4. 对多线程的详细解释二、初次实现多线程代码1. 初步了解2. 使用 Java 中的工具查看当前的所有线程3. Java 中创建线程的多种方式一、认识线程 1. 线程的概念 所谓线程,就是指在一个 ‘执行流…...

linux配置核查MySQL 配置规范 (Linux)_S3A3G3

linux的配置核查问题: 解决: 1.检查是否禁止mysql对本地文件存取 方法一:在my.cnf的mysql字段下加local-infile0 方法二:启动mysql时加参数local-infile0 /etc/init.d/mysql start --local-infile0 假如需要获取本地文件&#xf…...

Protobuf简介

Protobuf简介 1. Protocol Buffers1.1. 什么是Protocol Buffers?1.2. 选择你最喜欢的语言1.3. 如何开始2. Protocol Buffer Basics: C++2.1. 问题领域2.2. 在哪里找到示例代码2.3. 定义协议格式(Defining Your Protocol Format)1. Protocol Buffers Protocol Buffers(协议缓冲…...

【Kubernetes】第十七篇 - ECS 服务停机和环境修复

一,前言 上一篇,介绍了 Secret 镜像的使用; 三台服务每天大概 15 块钱的支出,用一个月也是不少钱; 闲时可以停掉,这样每天只有 4 块钱支出,剩下一大笔; ECS 服务停机后公网 IP 会…...

Vue2的生命周期(详解)

Vue的生命周期一、生命周期的概念二、钩子函数三、Vue2的生命周期3.1 初始化阶段3.2 挂载阶段3.3 更新阶段3.4 销毁阶段一、生命周期的概念 Vue实例的生命周期: 从创建到销毁的整个过程 二、钩子函数 Vue框架内置函数,随着组件的生命周期阶段,自动执行 作用:特定的时间点,执行特…...

Potions (Hard Version) and (Easy Version)(背包DP + 反悔贪心)

[TOC](Potions (Hard Version) and (Easy Version)) 一、Potions(Easy Version) 1、问题 2、分析(背包DP 贪心) 简而言之就是我们需要从左到右开始选数字,选的过程中我们需要保证我们选的数字的和始终是大于等于0的,在满足这个…...

剑指 Offer II 017. 含有所有字符的最短字符串

题目链接 剑指 Offer II 017. 含有所有字符的最短字符串 hard 题目描述 给定两个字符串 s和 t。返回 s中包含 t的所有字符的最短子字符串。如果 s中不存在符合条件的子字符串,则返回空字符串 ""。 如果 s中存在多个符合条件的子字符串,返回任…...

Modbus协议初探(C#实现)

由于作者水平有限,如有写得不对得地方请指正 趁着今天休息,就折腾一下Modbus协议,之前零零散散的看过几篇博客,听说搞上位机开发的要会这个协议,虽然我不是搞上位机开发的,但个人对这个比较感兴趣。按照我个…...

【华为OD机试2023】静态扫描 C++ Java Python

【华为OD机试2023】静态扫描 C++ Java Python 前言 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能最优),不能保证通过率。 Tips1:机试为ACM 模式 你的代码需要处理输入输出,input/cin接收输入、…...

函数栈帧的创建和销毁(详解)

函数栈帧的创建和销毁🦖函数栈帧是什么?🦖函数栈帧的创建和销毁解析🐋栈是什么?🐋认识相关寄存器和汇编指令🐋解析函数栈帧的创建和销毁🐳预备知识🐳函数的调用堆栈&…...

【100个 Unity实用技能】 | 脚本无需挂载到游戏对象上也可执行的方法

Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…...

条件期望5

条件期望例题 随机图 从节点1开始, N为一个随机变量, 表示整个过程第一次出现"贪吃蛇"情形时, 所进行的步数.即Nk⇒Xk(1)∈{1,X(1),X2(1),...Xk−1(1)}其中1,X(1),X2(1),...Xk−1(1)各不相同N k \Rightarrow X^k(1) \in \{1,X(1), X^2(1),...X^{k-1}(1)\} \\ 其中1…...

RecyclerView ViewType二级

实现效果描述: 1、点击recyclerview中item,列表下方出现其他样式的item,作为子item,如下所示 所需要的java文件和xml文件有: 1、创建FoldAdapteradapter, 在FoldAdapter中,定义两种不同的类型&#xff…...

将对象或数组存在 dom元素的属性上,最后取不到完整数据,只取到 [{

目录 一、问题 二、问题及解决方法 三、总结 一、问题 1.我需要在dom元素里面添加了一个属性test存一个对象数组temp,以便我下一次找到这个dom元素时可以直接拿到属性里面的数据来渲染页面。 2.dom 属性上存 对象和数组,必须先JSON.stringify(arr),转…...

Flask源码篇:Flask路由规则与请求匹配过程(超详细,易懂)

目录1 启动时路由相关操作(1)分析app.route()(2)分析add_url_rule()(3)分析Rule类(4)分析Map类(5)分析MapAdapter类(6)分析 url_rule_…...

Jmeter接口测试教程之【参数化技巧总结】,总有一个是你不知道的

目录:导读 一、随机值 二、随机字符串 三、时间戳 四、唯一字符串UUID 说起接口测试,相信大家在工作中用的最多的还是Jmeter。 大家看这个目录就知道jmeter的应用有多广泛了:https://www.bilibili.com/video/BV1e44y1X78S/? JMeter是一个…...

缓存与数据库的双写一致性

背景 在高并发的业务场景下,系统的性能瓶颈往往是出现在数据库上,用户并发访问过大,压力都打到数据库上。所以一般都会用redis做缓存层,起到一个缓冲作用,让请求先访问到缓存层,而不是直接去访问数据库&am…...

力扣-213打家劫舍II(dp)

力扣-213打家劫舍II 1、题目 213. 打家劫舍 II 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通…...

关于【网格结构】岛屿类问题的通用解法DFS(深度遍历)遍历框架+回溯+剪枝总结

最近在刷力扣时遇见的问题,自己总结加上看了力扣大佬的知识总结写下本篇文章,我们所熟悉的 DFS(深度优先搜索)问题通常是在树或者图结构上进行的。而我们今天要讨论的 DFS 问题,是在一种「网格」结构中进行的。岛屿问题…...

【LeetCode】982. 按位与为零的三元组

982. 按位与为零的三元组 题目描述 给你一个整数数组 nums &#xff0c;返回其中 按位与三元组 的数目。 按位与三元组 是由下标 (i, j, k) 组成的三元组&#xff0c;并满足下述全部条件&#xff1a; 0 < i < nums.length0 < j < nums.length0 < k < num…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...