多线程Thread(初阶二:Thread类及常⻅⽅法)

目录

一、Thread 的常⻅构造⽅法

继承Thread代码:

实现Runnable接口代码:

二、Thread 的⼏个常⻅属性

1、id:

2、获取线程的名字。

3、进程的状态:

4、在java中设置的优先级,

5、是否后台线程,

6、是否存活,

7、是否中断,

8、等待线程(结束),

9、获取线程的引用,currentThread()


一、Thread 的常⻅构造⽅法

最后一个线程组的概念是java的概念,和系统中的线程组不一样,不是同一个东西。

第一个和第二个构造方法在初阶一有介绍,

链接:多线程Thread(初阶一:认识线程)-CSDN博客

第三是创建一个线程,并且可以给这个线程命名,并不是它默认的Thread-0 / 1 / 2.....,第四个也是可以给线程对象命名,不过是使用接口的方法。

继承Thread代码:

class MyThread extends Thread {@Overridepublic void run() {System.out.println("hello thread1");}String name;public MyThread(String name) {super(name);this.name = name;}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t1 = new MyThread("这是我的线程");t1.start();Thread t2 = new Thread("这是我的线程"){@Overridepublic void run() {System.out.println("hello thread2");}};t2.start();}
}

执行效果:

两个线程:

上面两种的两种创建线程方式都可以。

实现Runnable接口代码:

class MyThread2 extends Thread {String name;public MyThread2(String name) {super(name);this.name = name;}@Overridepublic void run() {System.out.println("hello thread1");}
}
public class TestDemo2 {public static void main(String[] args) {Thread t1 = new MyThread2("这是我的线程1");t1.start();Thread t2 = new Thread("这是我的进程2") {@Overridepublic void run() {System.out.println("hello thread2");}};t2.start();}
}

执行效果:

两个线程:

注意:我们创建的线程如果不起名字,默认是Thread-0 1 2 3....,给不同线程起不同名字,对于线程的执行,没啥影响,主要是为了方便调试;线程之间的名字是可以重复的,在同一个工作中,需要多个线程完成,都可以起一样的名字;但是名字也不要乱起,最后要有一定的描述性。


二、Thread 的⼏个常⻅属性

1、id

jvm自动分配的身份标识,会保证唯一性。

2、获取线程的名字。

3、进程的状态

就绪状态、阻塞状态;线程也有状态,Java中对线程的状态进行了进一步的区分(比系统原生的状态更丰富一些)。

4、在java中设置的优先级

效果不是很明显,因为系统是随机调度的(对内核的调度器调度过程会产生一些影响)。

5、是否后台线程

也称为是否守护线程(比较抽象),所以记住和理解是否后台线程会轻松一些,与此相反,也有前台线程(和Android上的前台app,后台app完全不同)。

后台线程和前台线程的区别前台线程的运行,会阻止进程结束

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

我们创建的线程,默认是前台进程。

如下代码:

public class TestDemo3 {public static void main(String[] args) {Thread t = new Thread() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};t.start();}
}

执行效果:会不停的输出打印hello thread

那我们试着把这个线程设置为后台线程试试(默认为前台),代码:

public class TestDemo3 {public static void main(String[] args) {Thread t = new Thread() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};//在start之前,设置线程为后台线程(不能在start之后设置)t.setDaemon(true);t.start();}
}

执行效果:

根本就没有打印hello thread,进程就结束了,因为是后台进程,不会阻止进程的结束。

设为true是后台,后台,可以理解为背后,不出面的人,你感知不到;后台不会阻止进程结束。

不设为true是前台,前台,可以理解为明面上的人,你能感知到;前台会阻止进程结束。

6、是否存活,

isAlive( )表示内核中的线程(PCB)是否还存在。java代码中定义的线程对象(Thread)实现,虽然是表示一个线程,但这个对象本身的生命周期,和内核中的PCB生命周期  ,是不完全一样的。

isAlive的测试,代码:

public class TestDemo4 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println("start之前:" + t.isAlive());t.start();System.out.println("start之后" + t.isAlive());Thread.sleep(2000);System.out.println("t结束之后" + t.isAlive());}
}

执行效果:

解释:启动线程之前,也就是start之前,t这个实例线程是还没开始的,所以isAlive返回的是false,start后就查看这个线程存不存在,因为线程也刚启动,所以isAlive返回的是true,休眠两秒之后,t线程已经跑完了,所以isAlive返回的也是false。

7、是否中断

也是终止的意思。

下面写一个代码,用boolean类型的变量来控制while循环,也起到终止线程的作用。

public class ThreadDemo1 {private static boolean isQuit = false;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!isQuit) {System.out.println("我是一个线程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程工作完毕");});t.start();Thread.sleep(3000);System.out.println("让线程结束");isQuit = true;}
}

注意:这里的isQuit变量放在类中,不放在方法里作为局部变量的原因是涉及到了变量捕获如果放在main方法里,是局部变量,就必须要加 final 修饰将其变成常量为什么呢?这时因为main线程和我们创建的线程的栈帧生命周期不同,如果main线程先结束了,我们创建的线程要获取这个变量,但是我们main线程的栈帧生命周期已经结束了,我们拿不到这个变量,java这里的做法就比较暴力,直接把这个变量变成常量,要么这个变量就是全局变量,以至于不会发生上面的情况。

执行效果:

这时,我们也可以使用jdk里自带的方法:isInterrupted( )

代码如下:

public class ThreadDemo2 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("我是一个线程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("线程执行完毕");});t.start();Thread.sleep(3000);System.out.println("让线程结束");t.interrupt();}
}

执行效果:

这个线程并不会结束,会继续执行。

解释:可以看到这里抛出了个异常,而这个异常是InterruptedException 异常

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

这说明,sleep这出现问题了,为什么呢?原因是这个线程还在执行,main线程休眠3秒后,终止了这个线程,但sleep还没休眠够1秒,这里就会提前唤醒。

这里,提前唤醒,会做两件事:

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

2、清除 Thread 对象的 isInterrupt 标志位。(sleep清空标志位,是为了给程序猿更多的“可操作性空间”)。

所以,interrupt已经把标志位设置为true了,sleep被提前唤醒,清除了isInterrupt标志位后,就又把标志位设回了false,这个while循环还是能进去的,所以线程还在继续执行。

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

1、让线程立即结束。(加上break)

2、让线程不结束,继续执行。(不加break)

3、让线程执行一些逻辑后,再结束。(写一些其他代码,再加break)

对于一个服务器程序来说,稳定性很重要,这些所谓的“问题”,在java中就会以异常的形式体现出来,可以通过catch语句,对这些异常进行处理。主要的几种处理方式:

1、尝试自动恢复

2、记录日志

3、发出警报

8、等待线程(结束),

join( )。我们知道,多线程的执行顺序是不同的(随机调度,抢占式执行),有不可预期性,虽然线程的调度是无序的,但是我们可以调用一些api,来影响带线程的执行顺序,join就是一种方式,影响 线程结束 的先后顺序。比如:t2 线程等待 t1,这时,一定是 t1先结束,t2 后结束。这里的join就会使 t2 线程阻塞。

代码:

public class ThreadDemo3 {public static void main(String[] args) {Thread t = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("我是一个线程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程结束");});t.start();//t.join();System.out.println("这时一个主线程,在t线程结束后再执行");}
}

我们想让t线程执行完后再执行主线程,如果不写join方法。因为多线程的调度是随机性的,执行效果如下:

执行效果和我们预期的不一样,加上join方法后,

代码:

public class ThreadDemo3 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("我是一个线程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程结束");});t.start();t.join();System.out.println("这时一个主线程,在t线程结束后再执行");}
}

执行效果:

结果和我们想要预期效果相同。这里的join的意思是:让 t 线程执行完,再执行本线程。

这里是让main线程主动放弃去调度器调度,t 线程执行完后,main线程才执行,这也代表哪个线程调用join,哪个线程就是阻塞等待。这里就有了先后顺序。

注意:这里的先后顺序和优先级不同,优先级是系统调度器,在内核中完成的工作,即使优先级有差异,但是每个线程的执行顺序还是随机的(控制不了)。

等待线程结束还有两个重载方法,里面放的是要等待的时间,如图:

如果join不加参数,就是死等,第一个加参数的就是:等待多少毫秒,第二个加参数:数值精确到纳秒,不过很少用,因为计算机精确不到这么小。加参数是带有时间的等。

注意,有时候不想等,我们也可以不等,例如加 interrupt,可以终止这个等待,我们也可以在idea看到join的实现,是throws了 InterruptedException的。

9、获取线程的引用,currentThread()

我们对于一个类继承Thread是可以通过this拿到线程的实例的,

代码如下:

class MyThread extends Thread {@Overridepublic void run() {System.out.println("id:"+ this.getId() + " name:" + this.getName());}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();}
}

效果如下:

但是,如果是接口或者我们使用匿名内部类 / lambda表达式,就不能获取到Thread的引用了,这时,Thread已经给我们提供了方法获取引用了:Thread.currentThread()。如下展示:

代码:

public class ThreadDemo2 {public static void main(String[] args) {Thread t1 = new Thread(() -> {Thread t = Thread.currentThread();System.out.println(t.getId());});Thread t2 = new Thread(() -> {Thread t = Thread.currentThread();System.out.println(t.getName());});t1.start();t2.start();}
}

效果如下:


都看到这了,点个赞再走吧,谢谢谢谢谢!!!

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

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

相关文章

ubuntu22.04 arrch64版在线安装node

脚本 #安装node#下载node、npm国内镜像&#xff08;推荐&#xff09;# 判断是否安装了nodeif type -p node; thenecho "node has been installed."elsemkdir -p /home/zenglg cd /home/zenglgwget https://registry.npmmirror.com/-/binary/node/v10.14.1/node-v10.…

Linux系统编程 day04 文件和目录操作

Linux系统编程 day04 文件和目录操作 1. 文件IO1.1 open 函数1.2 close函数1.3 read函数1.4 write函数1.5 lseek函数1.6 errno变量1.7 文件示例1 读写文件1.8 文件示例2 文件大小的计算1.9 文件示例3 扩展文件大小1.10 文件示例4 perror函数的使用1.11 阻塞与非阻塞的测试 2. 文…

关于「光学神经网络」的一切:理论、应用与发展

/目录/ 一、线性运算的光学实现 1.1. 光学矩阵乘法器 1.2. 光的衍射实现线性运行 1.3. 基于Rayleigh-Sommerfeld方程的实现方法 1.4. 基于傅立叶变换的实现 1.5. 通过光干涉实现线性操作 1.6. 光的散射实现线性运行 1.7. 波分复用&#xff08;WDM&#xff09;实现线性运…

脉冲幅度调制信号的功率谱计算

本篇文章是博主在通信等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在通信领域笔记&#xf…

风口下的危与机:如何抓住生成式AI黄金发展期?

回顾AI的发展历程&#xff0c;我们见证过几次重大突破&#xff0c;比如2012年ImageNet大赛的图像识别&#xff0c;2016年AlphaGo与李世石的围棋对决&#xff0c;这些进展都为AI的普及应用铺设了道路。而ChatGPT的出现&#xff0c;真正让AI作为一个通用的产品&#xff0c;走入大…

Linux | 创建 | 删除 | 查看 | 基本命名详解

Linux | 创建 | 删除 | 查看 | 基本命名详解 文章目录 Linux | 创建 | 删除 | 查看 | 基本命名详解前言一、安装Linux1.1 方法一&#xff1a;云服务器方式1.2 方法二&#xff1a;虚拟机方式 二、ls2.2 ll 三、which3.1 ls -ld 四、pwd五、cd5.1 cd .\.5.2 ls -al5.3 重新认识命…

程序员兼职需要收藏的防坑技巧

不管你是刚刚上车的新职员&#xff0c;还是职场经营多年的老手&#xff0c;在零散时间&#xff0c;通过兼职搞一点零花钱&#xff0c;充实一下自己的生活&#xff0c;这是在正常不过的事情&#xff0c;但是很多同学害怕兼职有风险&#xff0c;被骗或者说找不到门路&#xff0c;…

优思学院|质量工程师在汽车行业待遇好吗?

优思学院认为质量工程师在汽车行业的待遇有可能相对较好的。随着中国汽车品牌在国内市场的崛起&#xff0c;特别是在电动汽车领域的增长&#xff0c;质量工程师在保障产品质量和安全性方面变得非常重要。由于中国汽车制造商对产品质量的高度重视&#xff0c;质量工程师在制定和…

AC自动机(简单模板)

AC自动机&#xff0c;就相当于是在字典树上用kmp。next数组回退的位置为最大匹配字符串在字典树上的节点位置。 在获取字典树上的next数组的时候用的是BFS每次相当与处理的一层。 下图中红线为&#xff0c;可以回退的位置&#xff0c;没有红线的节点回退的位置都是虚拟原点。…

基于C#实现线段树

一、线段树 线段树又称"区间树”&#xff0c;在每个节点上保存一个区间&#xff0c;当然区间的划分采用折半的思想&#xff0c;叶子节点只保存一个值&#xff0c;也叫单元节点&#xff0c;所以最终的构造就是一个平衡的二叉树&#xff0c;拥有 CURD 的 O(lgN)的时间。 从…

关于同一接口有多个不同实现的设计方案

关于同一接口有多个不同实现的设计方案 前言 最近公司做了一个银行相关的项目&#xff0c;告诉我公司对接了多个银行的支付&#xff0c;每个银行都有对应的接口要去对接&#xff0c;比如&#xff1a;交易申请&#xff0c;交易取消&#xff0c;支付&#xff0c;回单&#xff0…

rabbitMQ发布确认-交换机不存在或者无法抵达队列的缓存处理

rabbitMQ在发送消息时&#xff0c;会出现交换机不存在&#xff08;交换机名字写错等消息&#xff09;&#xff0c;这种情况如何会退给生产者重新处理&#xff1f;【交换机层】 生产者发送消息时&#xff0c;消息未送达到指定的队列&#xff0c;如何消息回退&#xff1f; 核心&…

麒麟KYSEC使用方法05-命令设置密码强度

原文链接&#xff1a;麒麟KYSEC使用方法05-命令设置密码强度 hello&#xff0c;大家好啊&#xff0c;今天给大家带来麒麟KYLINOS的kysec使用方法系列文章第五篇内容----使用命令设置密码强度&#xff0c;密码强度策略有两个文件需要修改&#xff0c;pwquality.conf/login.defs&…

命令执行总结

之前做了一大堆的题目 都没有进行总结 现在来总结一下命令执行 我遇到的内容 这里我打算按照过滤进行总结 依据我做过的题目 过滤system 下面是一些常见的命令执行内容 system() passthru() exec() shell_exec() popen() proc_open() pcntl_exec() 反引号 同shell_exec() …

大语言模型概述(三):基于亚马逊云科技的研究分析与实践

上期介绍了基于亚马逊云科技的大语言模型相关研究方向&#xff0c;以及大语言模型的训练和构建优化。本期将介绍大语言模型训练在亚马逊云科技上的最佳实践。 大语言模型训练在亚马逊云科技上的最佳实践 本章节内容&#xff0c;将重点关注大语言模型在亚马逊云科技上的最佳训…

解决Chrome浏览器无法启动,因为应用程序的并行配置不正确

目录 现象 方法1 方法2 附带&#xff1a;书签路径 一次比较奇怪的问题&#xff0c;花了一些时间&#xff0c;记录下来。 现象 进到本机默认安装路径&#xff1a; C:\Users\你的用户名\AppData\Local\Google\Chrome\Application 下面会有个版本号的目录&#xff0c;如我的…

快手ConnectionError

因为运行的程序被中断导致 top然后查看站用处内存高的accelerate kill进程号 9回车

linux基础5:linux进程1(冯诺依曼体系结构+os管理+进程状态1)

冯诺依曼体系结构os管理 一.冯诺依曼体系结构&#xff1a;1.简单介绍&#xff08;准备一&#xff09;2.场景&#xff1a;1.程序的运行&#xff1a;2.登录qq发送消息&#xff1a; 3.为什么需要内存&#xff1a;1.简单的引入&#xff1a;2.计算机存储体系&#xff1a;3.内存的意义…

微服务知识小结

1. SOA、分布式、微服务之间有什么关系和区别&#xff1f; 1.分布式架构指将单体架构中的各个部分拆分&#xff0c;然后部署到不同的机器或进程中去&#xff0c;SOA和微服务基本上都是分布式架构的 2. SOA是一种面向服务的架构&#xff0c;系统的所有服务都注册在总线上&#…

让工作效率提升10倍:十大AIGC工具评测【建议收藏】

AI技术的普及已经在近年来不断增长。这种技术已经改变了我们与电脑的互动方式&#xff0c;让我们能够更高效、更自然地完成任务。本文将展示10个基于ChatGPT、GPT-3.5和 GPT-4.0 AI模型构建的最强大的资源&#xff0c;使您更容易充分利用它们的潜力。因此&#xff0c;如果您想利…