【JavaEE初阶一】线程的概念与简单创建

1. 认识线程(Thread)

1.1 关于线程

1.1.1 线程是什么

        由前一节的内容可知,进程在进行频繁的创建和销毁的时候,开销比较大(主要体现在资源的申请和释放上),线程就是为了解决上述产生的问题而提出的方案;线程保持了独立调度执行,这样的“并发支持”,如此同时省去“分配资源”“释放资源”带来的额外开销。

        一个线程就是一个 "执行流". 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 "同时" 执行 着多份代码, 一个进程中可以并发多个线程,每条线程并行执行不同的任务。

1.1.2  为啥要有线程

1、首先, "并发编程" 成为 "刚需".

        单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源. 有些任务场景需要 "等待 IO", 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编 程.

2、其次, 虽然多进程也能实现 ,并发编程, 但是线程比进程更轻量.

        创建线程比创建进程更快.

        销毁线程比销毁进程更快.

        调度线程比调度进程更快.

3、最后, 线程虽然比进程轻量, 但是人们还不满足, 于是又有了 "线程池"(ThreadPool) 和 "协程" (Coroutine)

1.2 进程与线程

1.2.1 简单讲解

        下面来可能错误的分析一下进程与线程在创建和销毁的时候对内存地址的利用:

         下图我们用pcb来描述一个进程,图解如下:

        如上图所示,每一个进程在创建和销毁时都会在内存空间操作自己的地址,在进行多进程并发执行的时候,多个进程大规模的创建和销毁会再一定程度上消耗系统和操作系统的资源;

        下图我们来用pcb描述一下线程,图解如下图所示:

        pcb中有一个属性就是内存指针,如上图所示,多个线程的内存指针都指向内存地址中的同一个位置;

        这就意味着以上多个线程只有在第一个线程创建的时候需要从系统中分配资源,后序的线程就不需要继续在分配资源了,直接公用前面的那份资源就行了;

        同时除了内存之外,文件描述符(操作硬盘),也是多个线程共用一份的;当然我们也要注意不是所有的线程都能实现如上程度的资源共享的,只有我们设置的线程组才能实现资源共享;

        综上:线程的出现解决了频繁申请和释放资源的开销

 1.2.2 两者的关系

       没有进程的时候,进程扮演两个角色(资源分配的基本单位调度执行的基本单位

        引入了线程之后,进程只需要扮演一个角色(资源分配的基本单位),线程分担了一个角色的(调度执行的基本单位

        关于线程和进程的小结:

1、进程是包含线程的;

2、每一个线程也是一个独立的执行流,且可以执行一段代码,并且单独的参与到cpu调度中(状态,上下文,优先级,记账信息,每一个线程都有自己的一份)

3、每个进程有着自己独有的资源,进程中的线程公用这一份资源(内存空间和文件描述符)----->(进程是资源分配的基本单位,线程是调度执行的基本单位)

4、进程和进程之间,不会相互影响;如果一个进程的某个线程抛出异常,是可能会影响到其他线程的,由此会把整个进程中的所有线程都异常终止;

5、同一个进程中的线程之间,可能会相互干扰,从而引起线程安全问题;

6、当然线程不是越多越好,要能够合适,如果线程太多的话,调度开销就可能十分明显;

1.3 java线程和操作系统之间的关系

        线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库).

        Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装.

        所谓多线程编程:

        写代码的时候可以使用多线程进行并发编程(在java中不太推荐,很多和多线程编程相关的api在java标准库中都没有提供),也可以使用多线程并发编程(系统提供了多线程编程的api,java的标准库把这些api封装了,如此在代码中就可以使用了

        由此可以得出多线程在并发编程的时候,效率更高(频繁创建销毁的时候),尤其是对于java进程,是要启动java虚拟机的,如果启动java虚拟机,则这个事情的开销更大,--->可类似的看成搞多个java进程就是多个java虚拟机。

2. 初识多线程程序

        首先要有一个注意的点:

  • 每个线程都是一个独立的执行流
  • 多个线程之间是 “并发” 执行的

2.1 详细代码

        代码一:通过代码详细了解thread类:

        Java中提供的api,是通过thread这样的类进行展开的。

package thread;// 1. 创建一个自己的类, 继承自这个 Thread
class MyThread extends Thread {@Overridepublic void run() {// run 方法就是该线程的入口方法.System.out.println("圣诞节快乐,委婉待续!!!");}
}public class ThreadDemo1 {public static void main(String[] args) {// 2. 根据刚才的类, 创建出示例. (线程实例化, 才是真正的线程).// MyThread t = new MyThread();Thread t = new MyThread();// 3. 调用 Thread 的 start 方法, 才会真正调用系统 api, 在系统内核中创建出线程.t.start();}
}

        结果如下:

        代码二:编写mythread自定义类线程,在主线程中运行该自定义线程,代码如下:

package thread;
//1、创建一个自己的类,继承自这个thresd
class MyThread2 extends Thread{//重写run方法@Overridepublic void run() {//run 方法就是该线程的入口方法while (true){System.out.println("hello thread,委婉待续");try {Thread.sleep(1000);//休眠1000ms} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo2 {//创建一个main方法public static void main(String[] args){//2、根据刚才的类,创建出实例(线程实例,才是整整的线程)MyThread2 t = new MyThread2();//3、调用thread的start方法,才会整整的调用系统的api,在系统的内核中创建出线程池,//然后线程就开始运行我们的run方法中的代码t.start();while (true){System.out.println("hello main,smallye");try {Thread.sleep(1000);//休眠1000ms} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

        结果显示:

 

        结果显示交替进行,这就展现出了多线程与普通程序的区别

 2.2 代码深入分析:

2.2.1 一些问答

Q1:关于上图Thread类为啥能直接使用,而不需要进行导包?

A1:在java标准库中,有一个特殊的包,java.lang(这个包时默认被导的,这里面的类默认使用)

Q2:为啥我们自定义类mythread2前面没有public?可以加public吗?

A2:不能,一个.java文件中,只能有一个public的类,这个mythread类没有被public修饰,就是只能在当前包里被其他的类使用。

Q3:讲解一下run方法与main方法的区别?

A3:上图就类似于main方法,该run方法是一个java进程(程序)的入口方法(一般将“跑起来”的程序称为进程,没有运行起来的程序(.exe),称为“可执行文件”),且此处的run方法,不需要手动调用,会在合适的时候(此时是线程创建好了之后,即被实例化后),被jvm自动调用执行。(如此风格的函数,称为“回调函数callback”)

Q4:以上字符代表的含义?关于方法重写的含义?

A4:

1、首先上图字符是方法重写的注解,主要目的就是方便让编译器检查我们的代码是否构成方法重写(语法中有很多机制,就是让编译器对我们的代码进行检查,如果我们明确该方法是重写的,有了这个注解编译器就会检查我们的方法是否满足方法的重写,参数等是否满足方法重写的要求,这样就能够及时的报错,大大的提高了我们的工作效率)

2、方法重写:就是让你能够对现有的类,进行扩展,写出符合场景需求的具体方法。

我们写的以上线程,肯定是让这个线程执行一些代码的。Thread类本身就会带有一个人入口方法,但是很明显标准库自带的run是不知道我们的需求业务是啥样的,所以我们必须要手动指定(即写出一个具体的业务),这样就需要针对原有的Thread进行扩展,Thread会有很多属性方法,大部分内容复用即可,只要把需要扩展的内容进行扩展即可。

Q5:thread.sleep的作用?

A5:所谓sleep是java中封装后版本中thread中提供的静态方法,其主要作用就是让当前的线程进行休眠,时间单位是ms;

        当然sleep会出现java.lang.interruptedException异常,该异常出现的原因是我们要求休眠1000ms的线程会由于其他原因导致提前被唤醒,不能够休眠1000ms

Q5.1:下图中两个线程中的sleep为什么只有前者可以进行try-catch捕捉,而后者既可以进行try-catch捕捉,也可以进行抛出方法签名?

A5.1:正常情况下,一般受查异常既可以添加异常方法签名也可以使用try-catch捕捉;但是我们的前者sleep所在的mythread类中的run方法是要经过重写操作是具体实现的方法,如果我们添加了方法签名,那么由于语法所致,会让我们的方法不能构成重写操作;更有父类thread的run没有throws异常,所以子类重写的时候也不能有throws异常;

 2.2.2 多线程的运行逻辑

        如上图所示:

        在main方法中,主线程调用start方法(创建了t线程),此时cpu的两个核心开始运转,兵分两路,一方面执行沿着mian方法继续执行,即打印“hello main,smallye”;另外一方面,内核就通过刚才主线程api构造出t线程,并且执行run方法,即打印“hell0 thread,委婉待续”;同时这两个线程在同时执行的时候各论各的,互不干扰。

        但是正因为这样,所以考虑两个线程的执行顺序是一样的吗?

        其实这两个线程的执行顺序是不一样的,因为在操作系统的内核中,有“调度器”模块,该模块实现的方式是一种类似于“随机调度的”效果;

        所谓随机调度会导致以下两个后果:

        1、一个线程,被调到cpu上执行的时机是不确定的;

        2、上位到cpu里被执行的线程从cpu上下来的给别的线程上位的时机也是不确定的,如此就会导致线程“抢占式执行”,且当前的主流操作系统都是抢占式执行的;

        由于此案成创建本身是有开销的,故此在该开销本身的影响下,导致“hello main,smallye”会比“hell0 thread,委婉待续”快一点(大概率,但是不一定),综合题前所学,进程创建第一线程的时候开销是最大的,剩下的线程的开销都计较少;

2.3 使用 jconsole 命令观察线程

        我们可以使用jdk自带的工具 jconsole查看当前Java进程中所有的线程

        操作流程如下:

1、第一步,找到jdk

2、第二步,点进去,找到里面的bin文件点进去

3、第三步,点击bin文件夹里面的jconsole

4、第四步,找到你所创建进程

5、第五步,直接点击不安全连接就好

6、第六步,点击线程进行查看

        我们的t是指线程的变量名,所谓的看到的thread—0,是我们自定义线程的默认名字,一般会从0~n;

ps:本次的内容就到这里了,如果感兴趣的话就请一键三连哦!!!

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/577767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

apache禁止遍历目录

禁止Apache显示目录索引,禁止Apache显示目录结构列表,禁止Apache浏览目录,这是网上提问比较多的,其实都是一个意思。下面说下禁止禁止Apache显示目录索引的常见的3种方法。 要实现禁止Apache显示目录索引,只需将 Optio…

Jenkins的特殊操作定时自动执行任务以及测试报告调优

java -Dhudson.model.DirectoryBrowserSupport.CSP -jar Jenkins.war 测试报告 不美丽 执行上面的代码 重启jenkins 就好了

渗透笔记 (第一天 )

基础 操作系统和渗透名词 渗透名词 poc 概念验证 漏洞证明验证 exp 利用 利用系统漏洞进行攻击动作 唯一性 payload 有效载荷 在目标系统执行的代码和指令 (通道 ) shellcode shell代码 payload的一种 建立正向和反向的名字 &am…

Ai企业系统源码 Ai企联系统源码 商用去授权 支持文心 星火 GPT4等等20多种接口

智思Ai系统2.4.9版本去授权(可商用)支持市面上所有版本的接口例如:文心、星火、GPT4等等20多种接口!代过审AI小程序类目!!! 安装步骤: 1、在宝塔新建个站点,php版本使用…

Hive-数据模型详解(超详细)

文章目录 一、Hive数据模型1. 概述2. 数据库和表(1) 创建数据库(2) 使用数据库(3) 创建表格(4) 查看表结构 3. 分区与桶(1) 分区(2) 桶 4. 数据加载与查询(1) 数据导入(2) 查询语句 5. 总结 一、Hive数据模型 1. 概述 Hive是基于Hadoop的数据仓库工具,它提供了类似…

鸿蒙开发实战--DevEco Studio真机调试方法

DevEco Studio真机调试方法 1、 打开开发者选项 在手机设置菜单中点击【关于手机】选项。连续点击7次【版本号】进入开发者模式。返回设置菜单,在系统和更新中即可找到【开发人员选项】。 2、 开启USB调试 打开“设置”—“系统更新”—“开发者选项”&#xff…

使用pytorch神经网络拟合计算模型

一. 内容简介 python调用百度翻译api,将中文论文翻译英文,并保留部分格式 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3数据文件 链接:https://pan.baidu.com/s/1csJOoErGyx77MW_FImVKjg?pwd1234 三.主要流程 3.…

铁山靠之——HarmonyOS组件 - 2.0

HarmonyOS学习第二章 一、HarmonyOS基础组件的使用1.1 组件介绍1.2 Text1.2.1 文本样式1.2.2 设置文本对齐方式1.2.3 设置文本超长显示1.2.4 设置文本装饰线 1.3 Image1.3.1 设置缩放类型1.3.2 加载网络图片 1.4 TextInput1.4.1 设置输入提示文本1.4.2 设置输入类型1.4.3 设置光…

蓝桥杯-每日刷题-029

因子数与因子和 一、题目要求 题目描述 输入一个正整数N&#xff0c;求出这个数字存在多少个因子&#xff0c;以及因子之和。输入格式 存在多组测试数据&#xff0c;每组测试数据输入一个正整数N(1<N<10^9)输出格式 对于每组测试数据输出一行&#xff0c;包含两个数字&…

快速上手 Mac 电脑

更好的阅读体验 \color{red}{更好的阅读体验} 更好的阅读体验 触摸板操作 打开系统偏好设置-触控板选项查看学习常用操作双指触控实现鼠标右键功能建议打开轻点来点按&#xff0c;和 win 操作相同系统偏好设置-辅助功能-指针控制-触控板选项-启用拖移-三指拖移&#xff1a;单手…

王道考研计算机网络——数据链路层

码元和信号变化是一一对应的 低通&#xff1a;低于最高频率的可以通过 奈氏准则无噪声&#xff0c;香农定理有噪声 给出db&#xff0c;利用公式求出S/N 放到数字信道上传输就是基带信号&#xff0c;放到模拟信道上传输就是宽带信号 把基带信号调制成宽带信号之后&#xff0c;…

JSON在Java中的使用

目录 第一章、快速了解JSON1.1&#xff09;JSON是什么1.2&#xff09;json的语法格式①键值对、字符串、数字、布尔值、数组、对象②嵌套的格式 1.3&#xff09;为什么使用JSON 第二章、发送和接收JSON格式数据2.1&#xff09;postman发送JSON格式数据2.2&#xff09;Java后端接…

华为OD机试 - 可以处理的最大任务数(Java JS Python C)

题目描述 在某个项目中有多个任务(用task数组表示)需要你进行处理,其中: task[i] = [si, ei]你可以在 si ≤ day ≤ ei 中的任意一天处理该任务,请返回你可以处理的最大任务数。 输入描述 第一行为任务数量 n 1 ≤ n ≤ 100000后面 n 行表示各个任务的开始时间和终止时间…

【csapp】cachelab

文章目录 Part APart B32 * 3264 * 6461 * 67 实验全程参考大佬的博客CS:APP3e 深入理解计算机系统_3e CacheLab实验 &#xff0c;感觉大佬在矩阵转置那块介绍的还是有些简略&#xff0c;我自己又做了点动图加以补充理解。膜拜大佬&#xff01; Part A 先解决解析命令行参数的…

STM32实战之深入理解I²C通信协议

目录 IC的物理层 IC的协议层 IC特点 IC 总线时序图 软件模拟IC时序分享 例程简介 例程分享 STM32的IC外设 IIC&#xff08;Inter-Integrated Circuit&#xff09;&#xff0c;也称为IC或TWI&#xff08;Two-Wire Interface&#xff09;&#xff0c;是一种广泛使用的串行…

MyBatis——MyBatis的缓存

MyBatis的缓存 创建工程&#xff1a; 1缓存介绍 为什么使用缓存&#xff1f; 首次访问时&#xff0c;查询数据库&#xff0c;并将数据存储到内存中&#xff1b;再次访问时直接访问缓存&#xff0c;减少IO、硬盘读写次数、提高效率 Mybatis中的一级缓存和二级缓存&#xff1f;…

docker的常规使用总结

不安装docker下载镜像&#xff0c;或者下载异构镜像&#xff0c;模拟docker客户端 https://pull.7ii.win/ 1、启动docker服务 systemctl start docker 2、查看镜像 docker images 查看镜像centos-vim docker images | grep ubuntu-vim #强制删除全部镜像文件 docker rm…

linux 可睡眠RCU

可睡眠 RCU&#xff08; Sleepable RCU&#xff0c; SRCU&#xff09;允许在读端临界区里面睡眠。 在读端临界区里面睡眠&#xff0c;可能导致宽限期很长。为了避免影响整个系统&#xff0c;使用 SRCU的子系统需要定义一个 SRCU 域&#xff0c;每个 SRCU 域有自己的读端临界区…

【SD】通过种子数 差异强度 进行 角色融合【2】

通过 对 2个种子 进行对比 生成 2张图片 风格相符合的图片 best quality,masterpiece,chibi,full body, 我们首先生成1张图 Seed: 726932558 我们再次生成一张图 Seed: 3824894478 随机种子&#xff1a;图一 随机种子&#xff1a;图二 差异强度&#xff1a;0.2 差异强度0.4 差…

31. Ajax

简介 AJAX 是 Asynchronous JavaScript And XML 的简称。直译为&#xff0c;异步的JS和XML。AJAX的实际意义是&#xff0c;不发生页面跳转、异步载入内容并改写页面内容的技术。AJAX也可以简单的理解为通过JS向服务器发送请求。 AJAX这门技术很早就被发明&#xff0c;但是直到…