经过前面几篇文章的铺垫,相信大家对于多线程已经有了初步的了解,本篇将着重介绍多线程的封装类------Thread类
一、Thread类
我们知道,操作系统提供的原生API是使用C语言编写的,不同的操作系统针对线程的API还存在区别,Java作为基本适配所有操作系统的开发语言,对于上述不同操作系统的API进行了统一封装处理,即Thread类
API:Application Programming Interface 应用程序编程接口
Thread类是在java.lang包中,会默认直接导入
1. 常见的属性
属性 | 对应获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority |
是否是后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
1.1 ID
Java中给每个运行的线程分配了ID,用来标识线程身份的效果
1.2 名称
程序员自行给线程起的名字,一般用来标识线程具体的作用(具体如何起名字,详见下文Thread类的构造方法~)
1.3 状态
前文提到,进程有两个最为典型的状态------就绪状态和阻塞状态,Java对操作系统线程状态进行了重新封装表示
Java标准库中定义了一个枚举类型(Thread.State)来表示线程的几种不同状态
- NEW:安排了工作,但未开始行动
- RUNNABLE:可工作的,又可以分为正在工作和即将开始工作(即为就绪状态,可拆分为线程正在CPU上运行和线程随时可以去CPU上运行)
- BLOCKED:由于锁导致的阻塞,排队等着其他进程(锁这个概念后续会深入介绍)
- WAITING:没有超时时间的阻塞等待
- TIME_WAITING:指定时间的阻塞等待
- TERMINATED:工作完成了(内核中的线程已经结束了,但是Thread对象还在)
一张不是很清晰的图
线程状态这部分在了解线程的部分方法后可以更好地理解,这里只是先行介绍一下~
1.4 优先级
在操作系统层面,不同线程在CPU上执行的次序是由调度器决定的,这里说的优先级就相当于Java代码给调度器提供了一些建议,比如
java
Thread thread = new Thread();
// 设置优先级
thread.setPriority(7);
这个代码片段的作用就是将thread线程的优先级设置为7
需要注意的是,我们代码中设置的优先级只是给调度器的一个建议,具体线程的调度次序还是由调度器本身决定的,我们不能保证高优先级的线程一定能够最先开始执行
1.5 是否为后台线程
对应方法中的daemon意为守护,方法也可以视为"是否是守护线程",守护线程和后台线程本质上是一样的,只是翻译结果不同
这里先声明一个概念,main方法也有一个对应的线程,即为main线程
main线程结束后,其余线程仍然存在,这几个线程的存在就能使进程继续存在,这样的线程就成为前台线程
还有一些JVM自带的线程,它们的存在不影响进程的结束(即使他们继续存在,如果进程要结束,他们也会随之结束),这种线程即为后台线程,也就是守护线程
打个比方,进程是一家便利店,前台线程像收银台工作人员,直接对接顾客办理结账。只要还有收银员在服务,哪怕到了打烊时间,店铺也得继续营业 ------ 进程必须等所有前台线程完成才会结束
后台线程则像仓库补货员、清洁员,在后台做补货、打扫等支持工作。但只要收银台收尾完毕(前台线程结束),店铺就会关门,后台未完成的工作会随店铺关闭(进程结束)而中断,不影响进程的结束时机
关于前台线程和后台线程的说明:
- 前台线程和后台线程都有很多个
- 只有所有前台线程都结束了进程才会结束
- 自己代码创建的线程,包括main线程,都是默认前台线程
- 程序员可以修改线程的属性,但是需要在线程启动之前进行修改
1.6 是否存活
Java代码中创建的Thread对象和系统中的线程是一一对应的关系,但是Thread对象的生命周期和系统中线程的生命周期并不是完全同步的
对于这段代码
java
Thread t = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("thread running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("something wrong with t");
}
}
System.out.println("t 线程结束");
});
t线程在执行3s后结束了,也就是操作系统将这个线程销毁了,但是t这个对象还在(这里的定义采用了lambda表达式,后面还会详细介绍),也就是Thread对象的生命周期和系统中线程的生命周期不完全匹配
1.7 是否被中断
isInterrupted()方法就是用来检测当前线程的中断状态,返回一个boolean类型的变量,如果被中断返回true,未被中断返回false,通常用于线程内部检测是否收到中断请求,以便决定是否需要停止当前工作并退出
常用的方法和线程创建等相关内容,我们下节继续~