<JavaEE> Thread线程类 和 Thread的常用方法

目录

一、Thread概述

二、构造方法

三、常用方法

1.1 getId()、getName()、getState()、getPririty()

1.2 start()

1.3 isDaemon()、setDaemon()

1.4 isAlive()

1.5 currentThread()

1.6 Interrupt()、interrupted()、isInterrupted()

1.6.1 方法一:添加共享的标志位

1.6.2  方法二:使用内置的标志位

1.6.3 Java中终止线程不是强制性的

1.7 sleep()

1.8 join()


一、Thread概述

        Thread类是JVM用于管理线程的类,每一个线程都与一个唯一的Thread对象相关联,即每个执行流都由一个Thread对象进行描述,这些对象被JVM组织,用于线程调度和管理。

二、构造方法

构造方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable接口实现类对象,创建线程对象
Thread(String name)创建线程对象,并为线程对象命名
Thread(Runnable target, String name)使用Runnable接口实现类对象,创建线程对象,并为线程对象命名
Thread(TreadGroup group, Runnable target)指定线程组,使用Runnable接口实现类对象,创建线程对象

三、常用方法

常用方法说明
getId()获取线程ID
getName()获取线程名
getState()获取线程状态
getPririty()获取线程优先级
start()启动线程
isDaemon()判断线程是否为后台线程(守护线程)
setDaemon()设定线程是否为后台线程(守护线程)
isAlive()判断线程是否“存活”
currentThread()获取当前线程的引用
Interrupt()终止一个线程
interrupted()判断当前线程标志位状态
isInterrupted()判断对象线程标志位状态
sleep()休眠线程
join()阻塞线程

1.1 getId()、getName()、getState()、getPririty()

getId()
获取线程ID,ID是线程的唯一标识,由JVM自动分配并确保唯一性。
getName()
获取线程名,线程名可以自动生成,也可以自定义。线程名可以重复
getState()
获取线程状态,线程的状态有就绪、阻塞等。Java中现成的状态使用枚举保存,可以通过遍历枚举获得所有状态的描述

阅读指针 -> 《Java中线程有多少种状态(State)?状态之间的关系有什么关系?》

<JavaEE> Java中线程有多少种状态(State)?状态之间的关系有什么关系?-CSDN博客文章浏览阅读3次。介绍Java中的线程状态和状态之间的关系有什么关系。https://blog.csdn.net/zzy734437202/article/details/134626843

getPririty()
获取线程优先级,优先级高的线程理论上更容易被调度使用,但是在Java中优先级的效果并不明显。

操作演示:

class MyThread extends Thread{@Overridepublic void run() {for(int i=0;i<5;i++){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Thread_Demo6 {public static void main(String[] args){Thread thread = new MyThread();System.out.println("ID:"+thread.getId());System.out.println("线程名:"+thread.getName());System.out.println("状态:"+thread.getState());System.out.println("优先级:"+thread.getPriority());}
}

打印结果:

ID:20
线程名:Thread-0
状态:NEW
优先级:5

1.2 start()

start() 启动线程
1)通过重写Thread中的run方法可以创建一个线程对象,再通过调用start()方法,启动这个线程。此时,操作系统中的线程才真正被创建出来。
2)Thread调用start()创建出的线程,底层仍然是调用系统的API来进行创建线程的操作
3)Thread类使用start方法启动线程,对于同一个Thread对象,start方法只能调用一次,需要启动多少个线程,就需要创建多少个Thread对象。
4)start()和run()的区别在于,run方法是提供了线程需要运行的内容,而start方法才是真正让线程运行起来。

同一个Thread对象不能多次调用start方法演示:

class MyThread extends Thread{@Overridepublic void run() {for(int i=0;i<2;i++){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo9 {public static void main(String[] args) {Thread thread = new MyThread();//第一次启动线程thread;thread.start();//第二次启动线程thread;thread.start();}
}

打印结果:

Exception in thread "main" java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:708)
    at Learn_Thread.Demo9.Thread_Demo9.main(Thread_Demo9.java:32)

这是MyThread
这是MyThread
MyThread-run()运行结束


可以看到两次调用start方法,只有一次成功执行,另一次报错IllegalThreadStateException

1.3 isDaemon()、setDaemon()

isDaemon() 判断线程是否为后台线程
setDaemon() 设定线程是否为后台线程
1)daemon的意思是守护,因此也将后台线程称为守护线程。与后台线程相呼应,还有前台线程。
2)代码创建的线程,默认为前台线程。当setDaemon()方法的参数为false时,线程将被设置为前台线程,当参数为true时,线程将被设置为后台线程。
3)前台线程的运行时,将阻止进程结束;后台线程运行时,不会阻止进程结束。
4)因此为什么将后台线程称为守护线程?就是说进程需要我就在,进程不要我就走,在背后默默守护进程的线程嘛???

后台进程的执行演示:

class MyThread extends Thread{@Overridepublic void run() {for(int i=0;i<5;i++){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Thread_Demo7 {public static void main(String[] args) {Thread thread = new MyThread();//设置为守护线程(后台线程);thread.setDaemon(true);//开始thread;thread.start();//main线程等待两秒后结束,此时守护线程还有代码没打印,但也随之结束了;try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("main线程结束");}
}

打印结果:

这是MyThread
这是MyThread
main线程结束


启动main线程和thread线程,在main线程sleep两秒结束线程后,可以看到thread线程的run()方法打印结果确实不是预期中的五次“这是MyThread”。这意味着thread线程也随着main线程的结束而结束了。

1.4 isAlive()

isAlive() 判断线程是否“存活”
1)Java中的线程类Thread对象实例,虽然表示一个线程,但这个实例的生命周期与系统内核中的线程的生命周期是不同的。
2)Thread对象创建了就存在,但此时如果调用isAlive()得到的结果将会是false,因为内核中的线程此时还不存在。
3)只有当调用start()启动线程之后,内核中的线程启动,调用isAlive()得到的结果才会是true。
4)当线程运行结束,系统内核中的线程也随之结束,此时虽然Thread对象还存在,但是调用isAlive()得到的结果也将是false。

5)因此,可以简单将这个方法认为是用于判断系统内核中的线程(PCB)是否存在。

从代码层面来讲,可以认为是用于判断run()方法是否执行完毕。

演示判断线程是否“存活”:

class MyThread extends Thread{@Overridepublic void run() {for(int i=0;i<2;i++){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo8 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();//线程已有实例,判断isAlive();System.out.println("start前,thread是否存活:"+thread.isAlive());//启动线程,判断isAlive();thread.start();System.out.println("start中,thread是否存活:"+thread.isAlive());//等待run()执行结束,此时实例依旧存在,判断isAlive();Thread.sleep(5000);System.out.println("start结束,thread是否存活:"+thread.isAlive());}
}

打印结果:

start前,thread是否存活:false
start中,thread是否存活:true

这是MyThread
这是MyThread
MyThread-run()运行结束
start结束,thread是否存活:false

1.5 currentThread()

currentThread() 获取当前线程的引用
1)在currentThread()方法返回的打印信息中,有三个值,分别代表[线程名,线程优先级,所在线程组]。

获取线程引用操作演示:

public class Thread_Demo11 {public static void main(String[] args) {//打印main线程信息;System.out.println(Thread.currentThread());}
}

 打印结果:

Thread[main,5,main]


中括号中的三个值分别代表:线程名,线程优先级,所在线程组。

1.6 Interrupt()、interrupted()、isInterrupted()

如果想要中断(终止)一个线程,可以有多种方法,以下介绍两种:

方法一:通过共享的标志进行线程间沟通。
方法二:调用Interrupt()方法。

1.6.1 方法一:添加共享的标志位

class MyThread extends Thread{//设置共享的标志位;public volatile boolean isQuit = false;@Overridepublic void run() {//根据标志位的变化,决定后续执行;while (!isQuit){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo10 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();//启动线程;thread.start();//延时两秒后更改标志位;Thread.sleep(2000);((MyThread) thread).isQuit = true;}
}

打印结果:

这是MyThread
这是MyThread
这是MyThread
MyThread-run()运行结束

1.6.2  方法二:使用内置的标志位

方法说明
public void interrupt()

如果线程处于阻塞状态,则抛出异常;

如果线程不处于阻塞状态,则终止线程。

public static boolean interrupted()判断当前线程标志位状态。
public boolean isInterrupted()判断对象线程标志位状态。
1)上文由程序员手动设置了一个共享的标志位,用于控制线程的执行。Java中也提供了相应的封装好的方法,内置了标志位。使用以上三个方法,一样可以达到控制线程的执行效果。

通过Interrupt()终止线程,然后对线程标志位状态进行判断:

class MyThread extends Thread{@Overridepublic void run() {//使用isInterrupted()判断标志位状态;while (!Thread.currentThread().isInterrupted()){System.out.println("这是MyThread");//打印当前线程标志位的状态;System.out.println(Thread.interrupted());}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo12 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();thread.start();//延时两秒后更改标志位;Thread.sleep(2000);thread.interrupt();}
}

打印结果: 

......

这是MyThread
false
这是MyThread
false
这是MyThread
false
MyThread-run()运行结束


休眠两秒后,thread通过调用interrupt()方法修改了标志位,线程终止执行。

当更改标志位,但线程处于阻塞状态时:

        在更改标志位时,如果线程因为调用 wait/join/sleep 等方法而阻塞,则此时会抛出异常InterruptedException,并重置终止标志位。此时程序的后续执行通过catch子句中的异常处理方案来决定。
        如果在更改标志位时,线程非为阻塞状态,则标志位不会重置,可以通过interrupted()或isInterrupted()进行判断。
class MyThread extends Thread{@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo14 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();thread.start();//等待两秒后唤醒;Thread.sleep(2000);thread.interrupt();}
}

打印结果:

这是MyThread
这是MyThread
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at Learn_Thread.Demo14.MyThread.run(Thread_Demo14.java:16)

这是MyThread
这是MyThread
这是MyThread


可以看到,在抛出异常后,仍然继续打印,这意味着原先由interrupt()方法修改的标志位,在sleep唤醒时,又被重置为false了。

在异常处理中,加入更多的处理方法:

class MyThread extends Thread{@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//在异常处理中加入break,跳出循环;break;}}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo14 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();thread.start();//等待两秒后唤醒;Thread.sleep(2000);thread.interrupt();}
}

打印结果:

这是MyThread
这是MyThread
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at Learn_Thread.Demo14.MyThread.run(Thread_Demo14.java:16)

MyThread-run()运行结束


线程通过interrupt()方法修改了标志位,但由于线程此时大概率处于sleep(即,阻塞状态),因此,抛出异常,并将标志位重置。

这里线程会终止,是由异常处理中的break跳出循环得到的结果。

1.6.3 Java中终止线程不是强制性的

操作系统中的API:提供了强制终止线程的操作,无论线程执行到何种程度,都强行结束线程。
Java中的的API:终止线程需要对应线程互相配合,而不是直接“剪断”。
优劣:强制结束线程的方式更“随心所欲,为所欲为”,但如果线程执行过程中被强行终止,可能导致出现一些临时性质的“错误”数据。而相互配合的线程终止,虽然使终止线程时需要考虑的事情变多了,但也使得线程的终止更“安全”,系统运行更稳定了

1.7 sleep()

方法说明
public static void sleep(long millis) throws InterruptedException

以毫秒级别的精度,指定休眠时间

public static void sleep(long millis, int nanos) throws InterruptedException以纳秒级别的精度,指定休眠时间
1)sleep()方法只能保证实际休眠时间大于等于参数设置的休眠时间。
2)sleep被提前唤醒(如被上文的interrup唤醒)时,会抛出异常,并将Thread对象的标志位重置为false。

sleep被提前唤醒时,为什么要重置标志位?

sleep重置标志位,可以给程序员更多的“可操作空间”。

通过抛出异常,处理异常,程序的后续执行可以且不仅可以让线程立即结束,增加了代码的灵活性。

1.8 join()

join() 等待线程结束
join(long millis) 等待线程结束,指定最长等待时间
join(long millis, int nanos) 等待线程结束,以纳秒级别的精度指定最长等待时间
1)由于随即调度,抢占式执行,多线程的执行顺序是不确定的。但是通过应用程序中的API,可以影响到线程的执行顺序。
class MyThread extends Thread{@Overridepublic void run() {for(int i=0;i<5;i++){System.out.println("这是MyThread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("MyThread-run()运行结束");}
}
public class Thread_Demo13 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();thread.start();//让主线程阻塞,保证MyThread先运行完;thread.join();System.out.println("在MyThread结束后打印");}
}

打印结果:

这是MyThread
这是MyThread
这是MyThread
这是MyThread
这是MyThread
MyThread-run()运行结束
在MyThread结束后打印


可以看到,main线程中的“在MyThread结束后打印”确实是在thread线程结束后才打印的。


阅读指针 -> 《线程安全(重点!!)》

链接生成中..........

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

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

相关文章

stream流和方法引用

1.Stream流 1.1体验Stream流【理解】 案例需求 按照下面的要求完成集合的创建和遍历 创建一个集合&#xff0c;存储多个字符串元素把集合中所有以"张"开头的元素存储到一个新的集合把"张"开头的集合中的长度为3的元素存储到一个新的集合遍历上一步得到的集…

SIT65HVD75,可替代SN65HVD75,3.0~5.5V 供电,ESD 15kV HBM,20Mbps 半双工 RS485/RS422 收发器

SIT65HVD75 是一款 3.0V~5.5V 电源供电、总线端口 ESD 保护能力 HBM 达到 15kV 以上、 总线耐压范围达到 15V 、半双工、低功耗&#xff0c;功能完全满足 TIA/EIA-485 标准要求的 RS-485 收发 器。 SIT65HVD75 包括一个驱动器和一个接收器&#xff0c;两者均可…

模板上新|2023年10月DataEase模板市场上新动态

DataEase开源数据可视化分析平台于2022年6月正式发布模板市场&#xff08;https://dataease.io/templates/&#xff09;。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板&#xff0c;方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&#xff0c;并…

计算机网络——数据链路层-数据链路层概述(介绍、三个重要问题、使用广播信道的数据链路层、其他问题)

目录 介绍 三个重要问题 封装成帧 差错检测 可靠传输 使用广播信道的数据链路层 其他问题 介绍 本篇对数据链路层进行概述&#xff0c;我们首先来看看数据链路层在网络体系结构中的地位&#xff1a; 主机H1给主机H2发送数据&#xff0c;中间要经过三个路由器和电话网、…

单片机学习10——独立按键

独立按键输入检测&#xff1a; #include<reg52.h>sbit LED1P1^0; sbit KEY1P3^4;void main() {KEY11;while(1){if(KEY10) //KEY1按下{LED10; //LED1被点亮}else{LED11;}} } 按键 #include<reg52.h>#define uchar unsigned char #define uint unsigned intsbit …

使用Postman如何在接口测试前将请求的参数进行自定义处理

1、前言 当我们使用 Postman 进行接口测试时&#xff0c;对于简单的不需要处理的接口&#xff0c;直接请求即可&#xff0c;但是对于需要处理的接口&#xff0c;如需要转码、替换值等&#xff0c;则就麻烦一些&#xff0c;一般我们都是先手动把修改好的值拷贝到请求里再进行请…

干法制程中的辉光放电

在芯片制程中&#xff0c;几乎所有的干法制程&#xff0c;如PVD&#xff0c;CVD,干法刻蚀等&#xff0c;都逃不过辉光放电现象。辉光放电&#xff0c;是一种在低压下电离气体的过程&#xff0c;它在半导体制程中的许多重要步骤中有着核心作用。那您知道什么是“启辉”吗&#x…

Vue3使用kkFileView预览文件pdf

kkFileView - 在线文件预览kkFileView官网 - kkFileView使用Spring Boot搭建&#xff0c;易上手和部署&#xff0c;基本支持主流办公文档的在线预览&#xff0c;如doc,docx,Excel,pdf,txt,zip,rar,图片等等https://kkfileview.keking.cn/zh-cn/docs/usage.html业务场景&#xf…

【探索Linux】—— 强大的命令行工具 P.17(进程信号 —— 信号保存 | 阻塞信号 | sigprocmask() | sigpending() )

阅读导航 引言一、阻塞信号1. 信号相关常见概念&#xff08;1&#xff09;信号递达&#xff08;2&#xff09;信号未决&#xff08;3&#xff09;阻塞信号&#xff08;4&#xff09;忽略信号 2. 信号在内核中的表示⭕信号在内核中的表示示意图 3. sigset_t &#xff08;数据类型…

viple模拟器使用(三):unity模拟器中实现沿右墙迷宫算法

沿右墙迷宫算法原理 默认直行&#xff1b;右侧有路&#xff0c;则右转&#xff1b;前方无路&#xff0c;则左转。 由于unity模拟器中使用机器人移动动力控制和机器人转动角度控制来实现控制机器人前进、后退、暂停、左转、右转 。 程序编写 主机以及配置 通过内建事件初始化机…

云表|低代码助力职场人,一招制敌解决办公难题

身在职场&#xff0c;我们时常会面临一系列令人头疼的难题&#xff1a; ● 突然被领导要求30分钟内汇总所有人的填报信息&#xff0c;看着面前格式五花八门的Excel表格&#xff0c;我们无所适从&#xff0c;不知从何下手。 ● 在这个数字化的时代&#xff0c;公司仍然沿用古老的…

【数据中台】开源项目(2)-Davinci可视应用平台

1 平台介绍 Davinci 是一个 DVaaS&#xff08;Data Visualization as a Service&#xff09;平台解决方案&#xff0c;面向业务人员/数据工程师/数据分析师/数据科学家&#xff0c;致力于提供一站式数据可视化解决方案。既可作为公有云/私有云独立部署使用&#xff0c;也可作为…

【操作宝典】SQL巨擘:掌握SQL Server Management的终极秘籍!

目录 ⛳️【SQL Server Management】 ⛳️1. 启动登录 ⛳️2. 忘记密码 ⛳️3. 操作数据库和表 3.1 新建数据库text 3.2 新建表 3.3 编辑表 3.4 编写脚本 ⛳️【SQL Server Management】 ⛳️1. 启动登录 需要开启服务 ⛳️2. 忘记密码 登录windows--> 安全性 -->…

pikachu靶场:php反序列化漏洞

pikachu靶场:php反序列化漏洞 文章目录 pikachu靶场:php反序列化漏洞代码审计漏洞利用 代码审计 像这种反序列化的代码基本都是代码审计出的 // 定义一个名为S的类&#xff0c;该类有一个属性$test和一个构造函数 class S{ var $test "pikachu"; // $test是一个…

【1】AR Tag 在ros中的使用

1.定义 AR Tag 是一种用于增强现实&#xff08;AR&#xff09;应用中的视觉标记&#xff0c;用于跟踪和定位虚拟物体在现实世界中的位置。 AR Tag由黑白正方形图像表示&#xff0c;图像内部有黑色边框中的某些图案。它与我们经常用到的二维码长得类似&#xff0c;原理其实也一…

elementui的table合并列,三个一组

<el-table :span-method"objectSpanMethod" :cell-style"iCellStyle" :data"tableData" height"63vh" border style"width: 100%; margin-top: 6px"><el-table-column type"index" label"序号"…

5V摄像机镜头驱动IC GC6208,可用于摄像机,机器人等产品中可替代AN41908

GC6208是一个镜头电机驱动IC摄像机和安全摄像机。该设备集成了一个直流电机驱动器的Iris的PID控制系统&#xff0c;也有两个通道的STM电机驱动器的变焦和对焦控制。 芯片的特点: 内置用于Iris控制器的直流电机驱动器 内置2个STM驱动程序&#xff0c;用于缩放和…

Python内置函数与标准库函数的解释示例

一、内置函数与标准库函数的区分 Python 解释器自带的函数叫做内置函数&#xff0c;这些函数可以直接使用&#xff0c;不需要导入某个模块。 Python 解释器也是一个程序&#xff0c;它给用户提供了一些常用功能&#xff0c;并给它们起了独一无二的名字&#xff0c;这些常用功能…

汽车电子 -- 车载ADAS之RCTA(后方横向来车预警 )

国际标准: RCTA: GB/T XXXXX—XXXX 乘用车后部交通穿行提示系统性能要求及试验方法 一、后方横向来车预警RCTA&#xff08; Rear Cross Traffic Assist&#xff09; 在车辆倒车时&#xff0c;实时监测车辆后方横向接近的其它道路使用者&#xff0c;并在可能发生碰撞危险时发…

第20章多线程

创建线程 继承Thread 类 Thread 类时 java.lang 包中的一个类&#xff0c;从类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行&#xff0c;任务是指线程在启动时执行的工作&#xff0c;start() 方法启动线程&am…