【JavaEE初阶 — 多线程】Thread的常见构造方法&属性


目录

Thread类的属性

[1.Thread 的常见构造方法](#1.Thread 的常见构造方法)

[2.Thread 的几个常见属性](#2.Thread 的几个常见属性)

[2.1 前台线程与后台线程](#2.1 前台线程与后台线程)

[2.2 setDaemon()](#2.2 setDaemon())

[2.3 isAlive()](#2.3 isAlive())


Thread类的属性


  • Thread 类是JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的Thread 对象与之关联;
  • 每个执行流,也需要有一个对象来描述;
  • Thread类的对象就是用来描述一个线程执行流的,JVM会将这些Thread对象组织起来,用于线程调度,线程管理。

1.Thread 的常见构造方法


|--------------------------------------------|-------------------------------------------------------|
| 方法 | 说明 |
| Thread() | 创建线程对象,必须要重写 Thread类 的 run()方法 |
| Thread(Runnable target) | 使用 Runnable 对象创建线程对象 【不用重写 Thread类 的 run()方法】 |
| Thread(String name) | 创建线程对象,并命名 |
| Thread(Runnable target,String name) | 使用 Runnable对象创建线程对象,并命名 |
| Thread(ThreadGroup group, Runnable target) | 线程可以被用来分组管理,分好的组即为线程组 【这个目前我们了解即可】 |


对于 Thread类 的第四种构造方法,第一个参数传的是lamda表达式,lamda相当于Rannable;

再传入的第二个参数,就是这个线程的名字,需要手动添加**" "**

如果要调用:带有 自定义线程名字 的参数 的 构造方法,无论自定义的名字是什么,都不会不影响线程的执行的;为了方便程序员调试,可以给线程起名字。

程序运行后,我们可以通过 jconsole 这个工具,在线程列表中,看到自定义名字,并且正在运行的线程。除了自定义的线程,线程列表中的线程是JVM提供的线程。


如果我们不定义名字,程序调用 Thread类 的第一个构造方法,在jconsole的线程列表中,我们可以发现,如果不自定义线程名,系统会使用默认线程名 Thread - 数字 来命名线程。


如果在一个进程 中有多个线程,这些线程,会被CPU随机调度,并发执行;

所以不一定会因为主线程结束,整个进程也跟着结束。


2.Thread 的几个常见属性


|----------------------------------------------|---------------------|
| 属性 | 获取方法 |
| ID 【线程的唯一标识,不同线程不会重复】 | getId() |
| 名称 【各种调试工具都会用到】 | getName() |
| 状态 【表示线程当前所处的一个情况】 | getState() |
| 优先级 【优先级高的线程理论上来说更容易被调度到】 | getPriority() |
| 是否后台线程 【JVM会在一个进程的所有非后台线程结束后,才会结束运行】 | isDaemon() |
| 是否存活 【简单的理解为,run() 是否运行结束了】 | isAlive() |
| 是否被中断 | isInterrupted() |


2.1 前台线程与后台线程


如果在程序运行的过程中,我们通过 jconsole 查看线程列表中没有main,说明主线程已经结束;

主线程结束,但是 t1,t2,t3 还在,使用进程还在;说明 t1,t2,t3 能够影响进程是否终止。

所有类似 t1,t2,t3 这样能够有效进程存在的线程,称为 "前台线程"。

程序员通过代码创建的线程 和 主线程,都默认是前台线程。

总结:

  1. 能影响进程存在的,是前台线程;不能影响进程存在的,是后台线程;
  2. JVM会在一个进程的所有非后台线程结束后,才会结束运行

2.2 setDaemon()


程序员通过编写代码,创建的线程,包括main主线程,默认都是前台线程;

但是可以通过setDaemon(),将 前台线程 修改成 后台线程~~

上述代码的逻辑:主线程和 t 线程并发执行,并且主线程在打印三次" hello main "后,打印结束日志,而 t 线程继续执行死循环,所以进程没有因为主线程终止而结束。

所以,t 线程是一个前台线程,我们可以通过 isDeamon() 将 t 设置成后台线程;

通过 t.isDaemon(true) ,把 t 线程 从前台线程设置成后台线程;

此时,代码中只有主线程一个前台线程,所以在主线程运行结束后,整个进程结束,t 线程的死循环也被迫结束。

拓展:

进程与进程之间存在父子关系,而线程与线程之间则不存在;比如:

IDEA 本身也是一个 Java 进程;在 IDEA 中运行一个 Java 代码,通过IDEA 进程,又创建出一个新的Java 进程,这俩进程之间就是父子关系。


2.3 isAlive()


Java 代码中创建的Thread对象,和系统中的线程,是一 一对应的关系;

但是,Thread 对象 的生命周期,和 系统中的线程 的生命周期,是不同的~~

(可能存在:Thread对象 还存活,但是 系统中的线程 已经销毁 的情况)

我们引入一段代码,来看看"Thread对象还存活,但是系统中的线程已经销毁的情况"这种情况:

这个代码的逻辑:

前三秒 sleep1000毫秒 t线程的状态都是alive的状态,三秒后执行结束,t线程的isalive状态为false

线程的入口方法里的逻辑结束了,系统中对应的线程也就随之销毁了(操作系统) ;

虽然系统中的线程已经销毁,但是 Thread对象 还存活;

因此,t线程 被销毁,但是 t 这个对象依旧存在,所以才能一直通过t对象,调用isAlive方法


再多执行几次上述代码,发现程序运行结果中的 true 的个数是 3 还是 4 不固定,这是线程随机调度造成的:

主线程第四次打印,和 t线程 的结束,谁先谁后,是不一定的;

如果打印 true 的次数为4,说明在 第四次 主线程 和 t线程 并发执行的顺序是:

  1. 先执行主线程中的打印 t.isAlive
  2. 然后才执行 t线程 中的循环判断是否结束

所以 打印的第一个 false 是第五次执行线程,此时 t 线程已经凉透了~~


相关推荐
Dxy12393102162 分钟前
python使用requests发送请求ssl错误
开发语言·python·ssl
小林熬夜学编程6 分钟前
【Linux系统编程】第四十二弹---多线程编程全攻略:涵盖线程创建、异常处理、用途、进程对比及线程控制
linux·服务器·c语言·开发语言·c++
余华余华7 分钟前
Ngnix
java
昂子的博客13 分钟前
通过mybatis和mybatis plus 实现用户注册功能和基础的增删改查
java·开发语言·mybatis
£suPerpanda15 分钟前
牛客周赛 Round65 补题DEF
开发语言·数据结构·c++·算法·深度优先·动态规划·图论
KeithTsui22 分钟前
ZFC in LEAN 之 前集的等价关系(Equivalence on Pre-set)详解
开发语言·其他·算法·binder·swift
code .23 分钟前
C++各个版本的主要特性
开发语言·c++·现代c++
菜菜-plus23 分钟前
java设计模式之工厂模式
java·设计模式
哎呦没34 分钟前
健身行业创新:SpringBoot管理系统应用
java·spring boot·后端
暴怒香菜统治世界38 分钟前
数据结构--二叉树_链式(下)
c语言·开发语言·数据结构·算法·链表