线程的属性、状态、生命周期详解
Contents
一、线程简介
线程 (英语:thread)是操作系统能够进行运算调度的最小单位。 大部分情况下,它被包含在进程之中,是进程中的实际运作单位。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 在 Unix System V 及 SunOS 中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
我们运行 java 程序实际上就是运行了一个 jvm 进程,jvm 默认会用主线程来执行 main 方法,另外 jvm 里面还有负责垃圾回收的其他工作线程等等,java语言做了多线程的支持,也就是说我们可以使用多线程实现多任务。 现代计算机的 cpu 多采用多核架构,为了充分利用性能以及让耗时操作(读写文件等等)更有效率,所以在特定场合(高并发)需要多线程操作。
二、线程属性
- 线程是处理机调度的单位
- 多 cpu 计算机中,各个线程可以占用不同的 cpu
- 每个线程都有一个线程 ID、线程控制块(TCB)
- 线程类似进程也有就绪、堵塞、运行三种状态
- 线程几乎不拥有系统资源
- 同一进程的不同线程间共享进程的资源
- 由于共享内存地址空间资源,同一进程的线程间通信甚至无需系统干预
- 同一进程的线程切换,不会引起进程切换
- 切换同进程内的线程,系统开销很小
- 切换进程,系统开销很大
三、多线程模型
- 首先介绍线程的实现方式
- 用户级线程(User-Level Thread,ULT):由应用程序通过线程库实现。所有的线程管理工作都由应用程序负责(包括线程的切换),无需操作系统干预。
- 内核级线程(Kernel-Level Thread,KLT):线程管理工作由操作系统内核完成。线程调度、切换等工作都由内核负责。 可以说内核级线程就是"从操作系统内核视角可以看到的线程"。
只有内核级线程才是处理机分配的单位
- 多线程模型
由几个用户级线程映射到记个内核级线程的问题引出了"多线程模型问题"
模型包括三个:
- 多对一模型:多个用户级线程映射到一个内核级线程。开销小,效率高,但是并发度不高,不支持多核处理器并行。
- 一对一模型:一个用户级线程映射到一个内核级线程。并发程度高,但是开销大,效率低。
- 多对多模型:如下图,n个用户线程映射到m个内核级线程(n>=m)。每个用户进程对应 m 个内核级线程。集合了以上两个模型的优点。
四、线程生命周期
关于Java中线程的生命周期,首先看一下下面这张较为经典的图:
上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。主要包括:
Java线程具有五中基本状态
- 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
- 就绪状态(Runnable):当调用线程对象的
start()
方法t.start();
,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行; - 等待(Waiting):线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出特定动作(通知或中断);运行状态中的线程执行
wait()
方法; - 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
- 同步阻塞 – 线程在获取
synchronized
同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态; - 其他阻塞 – 发出了 I/O 请求时,线程会进入到阻塞状态。
- 同步阻塞 – 线程在获取
- 终止状态(Terminated):线程执行完了或者因异常退出了
run()
方法,该线程结束生命周期。
Java多线程的就绪、运行和死亡状态(注意点)
- 就绪状态转换为运行状态:当此线程得到处理器资源;
- 运行状态转换为就绪状态:当此线程主动调用
yield()
方法或在运行过程中失去处理器资源。 - 运行状态转换为死亡状态:当此线程线程执行体执行完毕或发生了异常。
此处需要特别注意的是:当调用线程的
yield()
方法时,线程从运行状态转换为就绪状态,但接下来 CPU 调度就绪状态中的哪个线程具有一定的随机性,因此,可能会出现 A 线程调用了yield()
方法后,接下来 CPU 仍然调度了 A 线程的情况。
Author 拾光
LastMod 2022-04-12