wordpress 代码行号/专业seo网站

wordpress 代码行号,专业seo网站,html5做的篮球网站,网站设计公司建设Thread 的常见构造方法 最后一个构造方法中的 ThreadGroup 线程组是 Java 中的概念,和系统内核中的线程组不是一个东西。我们自己创建的线程,默认是按照 Thread- 0 1 2 3 4...命名。但我们也可以给不同的线程,起不同的名字(不同的…

Thread 的常见构造方法

最后一个构造方法中的 ThreadGroup 线程组是 Java 中的概念,和系统内核中的线程组不是一个东西。我们自己创建的线程,默认是按照 Thread- 0 1 2 3 4...命名。但我们也可以给不同的线程,起不同的名字(不同的名字,对线程的执行,没有什么影响,主要是方便我们调试)

举例如下:

Thread 的几个常见属性

  1.  ID 是线程的唯一表示,JVM会自动进行分配,不同线程不会重复
  2.  名称是各种调试工具中,会使用到
  3.  状态表示线程当前所处的一个情况,进程有状态,分为就绪状态和阻塞状态。线程也有状  态,Java中对线程的状态,又进行了进一步的区分(比系统原生的状态,更丰富一些)
  4. 线程也有优先级,优先级高的线程,理论上来说更容易被调度到,但在Java中,效果其实并不是很明显(会对内核调度器的调度过程产生一些影响),总体上还是抢占式调度。
  5. daemon --> 线程守护,也可以称为是”后台线程“,和其对应的,还有”前台进程“(注意,这里的前台和后台,与Android系统上的前后台APP是完全不同的)

前台线程的运行,会阻止进程结束,后台线程的运行,不会阻止进程的结束

示例如下:

我们可以打开 jconsole 观察一下:

 上面示例代码在执行过程中, t 会持续进行(因为是while(true)死循环),但 main 已经结束了。jconsole 观察中,可以看到,除了我们创建的线程 Thread-0,其他都是JVM内置的线程,那些都是后台线程,不会阻止进程的结束。并且,在列表中,已经没有 main 线程了。按照我们之前的理解,main 执行完毕,进程应该结束,但很明显,此时这个进程仍然在继续执行中!

当我们强制结束,打印台线程显示如下的话,才表明进程结束了。

我们代码创建出来的进程,默认就是前台线程,会阻止进程结束,只要前台线程没执行完,进程就不会结束,即使 main 已经执行完毕了

但我们若是进行一些稍加改动,即在调用 start 方法之前,就调用 setDaemon 方法,设置进程为后台进程 

此时在重新运行程序,就会发现,控制台什么都没打印,进程就结束了。

setDaemon方法中,传入参数为 true ,则该线程为后台,不设 true,则是前台。

后台不会阻止进程的结束,前台会阻止进程的结束。

        6.isAlive(),即该线程是否存活表示了内核中的线程(PCB)是否还存在,Java代码中定义的线程对象(Thread)实例,虽然表示一个线程,但这个对象本身的生命周期,和内核中的 PCB 声明周期,是完全不一样的。

当执行这段代码之后,此时 t 对象是有了,但是内核中 PCB 还没有,isAlive 就是 false。

真正 t 调用 start方法,即 t.strat() 的时候,才真正在内核中 创建出这个PCB,此时 isAlive就是 ture了。当线程 run 执行完了,此时 内核中的线程 就结束了(内核PCB 就释放了),但是,此时 t 变量还存在,但 isAlive是 false。

示例代码:

打印结果:

Thread 类 使用 start 方法,启动一个线程,对于同一个 Thread 对象来说,start 方法只能调用一次。

示例代码:

运行程序之后:

虽然可以正常打印,但是会有报错的Exception

我们可以分析一下上面这个异常,IllegalThreadStateException,即非法的线程状态异常

面试题:start 和 run 的区别

本质上,strat 和 run 是八竿子打不着,互不相干的内容。

如图,我们有一个这样的代码:

在 main 函数中,调用 start 方法,结果如下:

如果注释掉 strat 方法,调用 run 方法,结果如下:

这里看起来的执行结果是一样的。但两个方法打印的时候,操作所在的线程的不一样的

t.strat() --> 这行代码是创建一个新的线程,由新的线程执行 hello

t.run() --> 这行代码的操作,仍然是在主线程中,打印的 hello

如果我们对代码进行一些修改:

打印结果就只有 hello thread,即代码此时就只能停留在 run 的循环中,下方 main 中的循环(打印 hello main 是无法执行的)

但如果此时是调用 t.start()

结果如下:

就会创建一个新的进程,然后在进程里面执行run循环,但因为 Java 是抢占式进程,此时就能够执行 main 中的循环。

终止一个线程

李四⼀旦进到⼯作状态,他就会按照⾏动指南上的步骤去进⾏⼯作,不完成是不会结束的。但有时我 们需要增加⼀些机制,例如⽼板突然来电话了,说转账的对⽅是个骗⼦,需要赶紧停⽌转账,那张三 该如何通知李四停⽌呢?这就涉及到我们的终止线程的⽅式了。

终止一个线程:即,让线程 run 方法(入口方法)执行完毕

那如何让线程提前终止呢?

核心问题也就是:如何让 run 方法能够提前结束呢?这就很取决于我们具体代码的实现方式了。

目前常见的有一下两种方式:

        1.通过共享的标记来进行沟通

        2.调用 interrupt() 方法来通知

引入:

我们也可以引入一个标志位 isQuite 如下图

通过上述代码,就可以让线程结束掉,具体什么时候结束,就取决于我们在另一个线程中的代码实现(即,在另一个线程中何时修改 isQuite 的值)

还有就是,在 main 线程中,要想让 t 线程结束,大前提,一定是 t 线程中的代码,对这样的逻辑有所实现,即有 isQuite 这种标志位,而不是 t 里面的代码随便怎么写,都能够随意提前结束的。

通过刚才的写法,其实是并不够优雅的,雷军好同志曾经说过,他大学期间的代码,优雅到诗一般,我们这个就比较拉跨了。

Thread 类还提供了一种更优的选择 -->  Thread 对象,内置了一个变量 --> currentThread

改进代码如下:

在这个代码中 while 循环中的参数是 Thread.currentThread().isInterrupted() 

其中,Thread.currentThread 操作是获取当前线程实例( t ),那个线程调用,得到的就是那个线程的实例,类似于 this,把我们引入中的 isQuite 改成判定 isInterrupter。

Thread.currentThread 补充:

该方法是获取到当前线程的引用(Thread的引用),如果是继承 Thread 类,就直接可以使用 This 来拿到线程实例,如果是 Runnable 或者 lambda 的方式,this 就无能为例了,此时 this 已经不再指向 Thread 对象了,就只能使用 Thread.currentThread()了。

下面的代码,本质上,是使用了 Thread 实例,内部自带的标志位,来代替刚才手动创建的 isQuit变量了,最后一行代码 t.interrupt() 就相当于 isQuit = true了。

执行代码如下:

可以看到,代码执行到了14行的时候,出现了一个异常,并且 t 线程 并没有真的结束。

我们研究报出的异常 InterruptedException 这不就是 try - catch 中的吗?

再观察报出的异常:

好像是这里的 interrupt 导致 sleep 出现了异常

如果没有 sleep interrupt ,线程是可以顺利结束的,但有了 sleep 就引起了变数。

在执行 sleep 的过程中,调用了 interrupt,大概率是 sleep 的休眠时间还没有到,就被 interrupt 提前唤醒了。

sleep 提前被唤醒,会做两件事:

        1. 抛出 InterruptedException (紧接着就会被 catch 获取到)

        2. 清除 Thread 对象的 isInterrupted 标志位

通过 interrupt 方法,已经把标志位设置位 true 了,但是 sleep 提前被唤醒之后,又会清除 Thread 对象的 isInterrupted 标志位,即又把标志位设回 false 了,所以此时循环还是会继续执行了。

如果我们想要让线程结束的话,只需要在 catch 中 加上 break 就可以了。

结果如下:

这样,循环就可以结束了。但还是会报出Exception,但这个日志是我们代码中 e.printStackTrace()中打出来的,如果我们不写打印,就不会存在了。

sleep 清空标志位,是为了给程序员更多的“可操作空间”的。前一个代码,写的是 sleep(1000),结果现在, 1000 还没有到,就要终止线程,这就相当于是两个前后矛盾的操作,此时,也是需要更多的代码,来对这样的情况进行具体处理的。

此时程序员就可以在 catch 语句中,加入一些代码,来做一些处理。

        1. 让线程立即结束 --> break

        2. 让线程不结束,继续执行 --> 不加 break

        3. 让线程执行一些逻辑之后,再结束 --> 写一些其他的代码,再 break

对 try - catch 块的补充:(在实际开发中, catch 里应该要写什么样的代码???如果程序出现了异常,该如何处理,是更加合理的???)

对于一个服务器来说,稳定性,是十分重要的,我们无法保证服务器一直不出问题,这些所谓的“问题”,在 Java 代码中,就会以 异常的形式体现出来,可以通过 catch 语句,对这些异常进行处理。

        1. 尝试自动恢复。能自动恢复,就尽量自动恢复。比如出现了一个网络通信相关的异常,我们就可以在 catch 中尝试重新连接网络。

        2. 记录日志(异常信息记录到文件中)有些情况,并非是很严重的问题,只需要把这个问题记录下来即可(并不需要立即解决),等到后面程序员有空闲的时候,再进行解决。

        3.发出报警。这个是针对一些比较严重的问题了,包括但不限于,给程序员 发邮件,发短信,发微信,打电话等等.......

        4. 也有少数正常的业务逻辑,会依赖到 catch (比如文件操作中 有的方法,就是要通过 catch 来结束循环...)(非常规用法)

在 Java 中, 线程的终止,是一种“软性”操作,必须要对应的线程去进行配合,才可以把终止落实下去。

相比之下,系统原生的 API 其实提供了强制终止线程的操作。无论线程是否愿意配合,无论线程执行到了那行代码,都能够强行的把线程给干掉!!

这样的操作,Java  的 API 是没有提供的,上述强制执行的做法,利大于弊。

如果要强行终止一个线程,很可能线程执行到一般,就被强制终止,会出现一些残留的临时性质的“错误”的数据。比如这个线程正在执行写操作,写文件的数据有一定的格式要求(写一个图片文件) --> 如果写图片写了一般,线程被终止了,图片就尴尬了,图片文件是存在的,里面的内容不正确,无法正确打开了。

private static boolean isQuit = false

如果把 isQuit 作为 main 方法中的局部变量,是否可行? -- > 不可行。

这是我们在 lambda 表达式中曾经研究过的一个语法 -- > 变量捕获

lambda 表达式 / 匿名内部类 是可以访问到 外面定义的局部变量的(变量捕获规则)

报错信息告诉我们,捕获的变量,必须是 final 修饰的 或者是 “事实”final(即虽然没写 final 但是没有修改), 但is Quit 又必须要修改!!!此处的 final,也不是“试试”final,所以局部变量这一手,是行不通的。

因此,必须写成成员变量。那为什么,写成成员变量就行得通了呢?这又是那个语法规则呢?

lambda表达式,本质上是“函数式接口“ ==》 匿名内部类。 内部类来访问外部类的成员,这个事情本身就是可以的,这个操作就不受到变量捕获的影响了。

那为什么,Java 对于变量捕获操作,有 final 的限制呢???

isQuite 是局部变量的时候,是属于 main 方法的栈帧中,但是 Thread lambda 是由自己独立的栈帧的(是另一个线程中的方法),这两个栈帧的生命周期是不一致的。

这就可能导致 --> main 方法执行完了,栈帧就销毁了,main 方法执行完了,栈帧就销毁了,但此时 Thread 的栈帧还在,还想继续使用 isQuit。Java 中的做法就非常的简单粗暴,变量捕获的本质上就是传参,换句话说,就是让 lambda 表达式在自己的栈中创建一个新的 isQuit,并把外面的 isQuit 值给拷贝过来(为了避免 isQuit 的值不同步, Java 干脆就不让 isQuit 修改)。

等待一个线程 - join()

有时候,我们需要等待一个线程完成它的工作之后,才能进行自己的下一步工作。例如:张三只有等李四转账成功之后,才能对现在的吃饭行为进行付款,这时候,我们需要一个方法明确的等待线程的结束。

多个线程的执行顺序是不固定的(随即调度,抢占式执行),虽然线程底部的调度是无序的,但是可以在应用程序中,通过一些 API,来影响到线程执行的顺序。 --> join 就是一种方式,影响线程结束的先后顺序。比如,t2 线程等待 t1 线程,此时,一定是 t1 线程先结束,t2 线程后结束,其中就使用到 join 使得 t2 线程阻塞。

示例代码:

打印结果如下:

补充:

如果不适用 join,使用 sleep,是具有随机性的,如果将 join 换位 sleep,如下:

在 sleep 5 秒之后,是先打印”这是主线程“还是先打印”线程执行完毕“,是无法确定的。虽然,我们可以进行修改,sleep 中的参数可以传为 6000,这也是一个办法,但是不完全可行,我们给 sleep 传参数,是能够对线程 t 的执行时间有一个预期,才能这样些,如果都不知道 t 要执行多久,那 sleep 的参数就没办法传了。所以最好的办法还是 join 方法,让 main 线程等待 t 线程结束【谁等谁,一定要分清楚,在那个线程中调用 join 方法,就是在 那个线程中等待 调用 join 方法的线程,如上图例子,在 main 线程中,t 线程调用 join 方法,则是 main 线程 等待 t 线程】。

执行 join 的时候,就看 t 线程是否正在运行,如果 t 运行中,main 线程就会阻塞(main 线程就暂时不去参与 CPU 执行了),如果 t 运行结束, main 线程就会总阻塞中恢复过来,并且继续往下执行。(阻塞:使得线程的结束时间,产生了先后关系。)

补充:

        1.这个 join 阻塞和优先级还是不同的。优先级,是系统调度器在内核中完成的工作,即使优先级有差异,但是每个线程的执行顺序仍然是随机的。

线程优先级是调度器的重要参考,但实际执行顺序还受调度策略、时间片、线程状态、资源竞争等因素影响。优先级决定的是线程获取 CPU 的 “机会”,而非绝对顺序。因此,即使优先级有差异,线程执行顺序仍可能表现出随机性。

上述线程结束顺序的先后,在代码中,是通过 API 来控制的,让 main 线程,主动放弃了去调度器中调度,其中 t 线程 虽然也可能和其他线程共同进行调度,但由于主线程一直在等待,即使 t 线程中间经历了多次 CPU 的切换,仍然不影响 t 线程最终能够正确先执行完毕。

join 方法中,也是可以有参数的,若没有参数,我们称为“死等”,就必须要要等待线程结束,再进行当前线程,这是机器不科学的,尤其是再我们的计算机中(如果我们的代码中,因为死等,导致程序卡住了,无法继续处理后面的逻辑,这是一个非常严重的 bug !)

若传入一个参数,就是带有超时时间的等,等操作是由一个时间上限的,等待的时间达到超时时间,就不等了,该干啥干啥了。

完!

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

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

相关文章

Java基础关键_032_反射(二)

目 录 一、反射 Class 的 Method 1.反编译 String 类的方法签名 2.通过反射调用方法 3.反编译 String 类的构造方法签名 4.通过反射调用构造方法 二、类加载过程 1.装载(Loading) (1)说明 (2)双亲委…

《数据结构:单链表》

“希望就像星星,或许光芒微弱,但永不熄灭。” 博主的个人gitee:https://gitee.com/friend-a188881041351 一.概念与结构 链表是一种物理存储上非连续、非顺序的存储结构,数据元素的顺序逻辑是通过链表中的指针链接次序实现的。 单…

蓝桥杯 - 中等 - 绝美宋词

介绍 “今宵酒醒何处,杨柳岸晓风残月”,“蓦然回首,那人却在灯火阑珊处”,“试问闲愁都几许?一川烟草,满城风絮,梅子黄时雨” ...... 宋词可谓是古代文学桂冠上一颗璀璨的明珠,本题…

JDBC、excute()、DriveManager、Connection、Statement、自建JDBC工具类、占位符

DAY19.2 Java核心基础 JDBC JDBC:Java database Connectivity JDBC是java程序连接各种数据库的组件 Mybatis就是基于JDBC的封装,是独立于数据库的管理系统,通用的SQL数据库存取和操作的公共接口 定义了一套标准,为访问 不同数…

21天Python计划:函数简单介绍

文章目录 前言一、函数知识体系二、函数基础函数的定义和调用函数参数 三、函数对象、函数嵌套、名称空间与作用域、装饰器函数对象函数嵌套名称空间与作用域装饰器 四、迭代器、生成器、面向过程编程迭代器生成器面向过程编程 五、三元表达式、列表推导式、生成器表达式、递归…

污水处理厂人员定位方案-UWB免布线高精度定位

1. 方案概述 本方案采用免布线UWB基站与北斗卫星定位融合技术,结合UWBGNSS双模定位工卡,实现污水处理厂室内外人员高精度定位(亚米级)。系统通过低功耗4G传输数据,支持实时位置监控、电子围栏、聚集预警、轨迹回放等功…

无人机DSP处理器工作要点!

一、DSP处理器在无人机中的工作要点 1. 高效运算架构 哈佛结构:DSP采用程序与数据存储分离的哈佛结构,允许同时访问指令和数据,提升数据吞吐效率。 流水线技术:将指令分解为取指、译码、执行等多个阶段并行处理&#xff0c…

MySQL查询成本计算

对于如上SQL,只是因为查询字段不同,最终执行时选择的索引就不同,那么MySQL是如何决定选择使用哪个索引呢? 答案是MySQL会进行成本计算,对于各个场景查询进行成本预估,最终选择最优。 我们可以使用trace工具…

《K230 从熟悉到...》矩形检测

《K230 从熟悉到...》矩形检测 《庐山派 K230 从熟悉到...》矩形检测 矩形检测技术是一种广泛应用于电子图像处理的核心技术。它通过识别和分析图像中的矩形结构,为各种应用提供基础支持。从传统图像处理算法到现代深度学习技术,矩形检测的实现途径多种多…

python基础学习三(元组及字符串的使用)

文章目录 元组什么是元组元组的创建方式为什么要将元组设计成不可变序列元组的遍历集合集合的相关操作集合操作集合的数学操作集合生成式列表,字典,元组,集合总结 字符串字符串的驻留机制判断字符串的操作方法字符串的比较操作字符串的切片操…

爬虫工程师分享自动批量化获取商品评论数据的方法有哪些?

在电商领域,商品评论数据对于商家了解产品口碑、洞悉用户需求,以及开展竞品分析等工作具有极其重要的价值。作为爬虫工程师,掌握自动批量化获取商品评论数据的方法,能极大提升数据收集效率。下面,我将分享一些实用的操…

Vue3组件事件用户信息卡练习

用户信息卡 题目要求 实现一个用户信息卡系统&#xff0c;包含以下功能&#xff1a; 1.父组件收集用户信息&#xff08;姓名、年龄、班级&#xff09; 2.子组件接收并展示用户信息卡片 3.添加基本的数据验证 <!DOCTYPE html> <html lang"en"> <h…

SpringBean模块(二)bean初始化(2)和容器初始化顺序的比较--引入ApplicationContextInitializer

前面介绍了获取容器可以让spring bean实现ApplicationContextAware&#xff0c;实际也是初始化执行了setApplicationContext接口&#xff0c; 初始化接口还可以借助一些注解或者spring bean的初始化方法&#xff0c;那么他们的执行顺序是什么样的呢&#xff1f; 一、验证&…

中小型企业网络的搭建

1.1 网络逻辑拓扑、布线方案的设计 1.1.1 网络设计依据 网络设计应遵循以下基本原则&#xff1a; 高效性&#xff1a;确保网络架构能够支持企业日常业务的高效运行。 可靠性&#xff1a;采用冗余设计&#xff0c;确保网络的高可用性&#xff0c;避免单点故障。 可扩展性…

angr基础学习

参考&#xff1a;angr AngrCTF_FITM/笔记/03/Angr_CTF从入门到精通&#xff08;三&#xff09;.md at master ZERO-A-ONE/AngrCTF_FITM angr_explore 00_angr_find IDA分析结果&#xff1a; 逻辑简单&#xff0c;输入&#xff0c;complex_function进行加密&#xff0c;加密…

软考-高级-系统架构设计师【考试备考资料下载】

计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试是原中国计算机软件专业技术资格和水平考试的完善与发展。计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试是由国家人力资源和社会保障部、工业和信息化部领导下的国家级考试。 计算机技术与软件专…

3. 第三放平台部署deepseek

有时候我们会发现使用deepseek服务器&#xff0c;异常卡顿&#xff0c;这是由于多方面原因造成的&#xff0c;比如说访问人数过多等。想要解决这个问题&#xff0c;我们可以选择第三方平台进行部署 第三方平台 我们可以选择的第三方平台很多&#xff0c;比如硅基流动、秘塔搜索…

1.4-蜜罐\堡垒机\API接口

1.4-蜜罐\堡垒机\API接口 蜜罐&#xff1a;用来钓鱼或诱惑测试人员的防护系统 bash <(curl -sS -L https://hfish.net/webinstall.sh) # 安装HFISH蜜罐堡垒机&#xff1a; 运维用的&#xff0c;统一管理运维平台;拿下堡垒机就很有可能等于拿下了多个平台 jumpServer一键安…

知识图引导的检索增强生成

摘要 检索增强生成&#xff08;RAG&#xff09;已经成为一种很有前途的技术&#xff0c;用于解决大型语言模型&#xff08;LLM&#xff09;生成的响应中的幻觉问题。现有的RAG研究主要集中在应用基于语义的方法来提取孤立的相关组块&#xff0c;忽略了它们之间的内在关系。在本…

【机器学习】imagenet2012 数据预处理数据预处理

【机器学习】数据预处理 1. 下载/解压数据2. 数据预处理3. 加载以及训练代码3.1 使用PIL等加载代码3.2 使用OpenCV的方式来一张张加载代码3.3 h5的方式来加载大文件 最后总结 这个数据大约 140个G,128w的训练集 1. 下载/解压数据 首先需要下载数据&#xff1a; 数据最后处理…