10 张图聊聊线程的生命周期和常用 APIs
上一篇文章我们聊了多线程的基础内容,比如为什么要使用多线程,线程和进程之间的不同,以及创建线程的 4 种方式。本文已收录至我的 Github: https://github.com/xiaoqi6666/NYCSDE
今天我们来说一下线程的生命周期和常用 APIs:我们需要非常清楚的知道线程的各种状态,比如排查程序运行慢的原因时,就需要看下是不是哪里被阻塞了;另外它也是面试时非常喜欢问的,如果基础内容都答不好,恐怕直接就挂了。
本文分为两大部分,
线程的 6 大状态; 多线程常用的 APIs: join() wait() notify() yield() sleep() currentThread() getName() getId() getPriority() setPriority() stop()
线程状态
关于线程的状态,网上各种说法都有,比较流行的是 5 种或者 6 种。关于 5 种状态的那个版本我没有找到理论依据,如果有小伙伴清楚的也欢迎留言指出。
我这里所写的是根据 java.lang.Thread
的源码,线程有以下 6 大状态:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITTING,
TIMED_WAITTING,
TERMINATED;
}
先上图,我们再依次来看。

1. New
A thread that has not yet started is in this state.
就是指线程刚创建,还没启动的时候,比如刚 new
了一个 thread
。
MyThread myThread = new MyThread();
2. Runnable
A thread is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.
那么接下来,自然就是要启动线程了,也就是调用 thread
的 start()
方法。
myThread.start();
启动之后,线程就进入了 Runnable
状态。
此时所有的线程都会添加到一个等待队列里,等待“CPU 调度”。
如果抢占到 CPU 的资源,那就执行;如果没抢到,就等着呗,等当前正在执行的线程完成它能执行的时间片之后,再次抢占。
要注意这里在等待的一般是系统资源,而不是锁或者其他阻塞。
3. Blocked
Thread state for a thread blocked waiting for a monitor lock.
A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after callingwait()
Object.
这里给出了非常明确的 use case
,就是被锁在外面的才叫阻塞。所以这里必须要有至少 2 个线程。
4. Waiting
A thread in the waiting state is waiting for another thread to perform a particular action.
那具体有哪些原因呢?
A thread is in the waiting state due to calling one of the following methods:
Object.wait with no timeout Thread.join with no timeout LockSupport.park
所以说,当调用了
wait()
,join()
,park()
方法之后,线程进入等待状态。
这里的等待状态是没有时间限制的,可以无限的等下去... 所以需要有人来唤醒:
如果是通过 wait()
进入等待状态的,需要有notify()
或者notifyAll()
方法来唤醒;如果是通过 join()
进入等待状态的,需要等待目标线程运行结束。
比如在生产者消费者模型里,当没有商品的时候,消费者就需要等待,等待生产者生产好了商品发 notify()
。下一篇文章我们会细讲。
5. Timed_waiting
导致这个状态的原因如下:
Thread.sleep Object.wait with timeout Thread.join with timeout LockSupport.parkNanos LockSupport.parkUntil
其实就是在上一种状态的基础上,给了具体的时间限制。
那么当时间结束后,线程就解放了。
6. Terminated
A thread that has exited is in this state.
这里有 3 种情况会终止线程:
执行完所有代码,正常结束; 强制被结束,比如调用了 stop()
方法,现在已经被弃用;抛出了未捕获的异常。
线程一旦死亡就不能复生。
如果在一个死去的线程上调用 start()
方法,那么程序会抛出 java.lang.IllegalThreadStateException
。
接下来我们说说多线程中常用的 11 个 APIs。
APIs
1. join()
join()
方法会强制让该线程执行,并且一直会让它执行完。
比如上一篇文章的例子是两个线程交替执行的,那么我们这里该下,改成调用小齐线程.join()
,那么效果就是先输出 小齐666
。
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println("小齐666:" + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new MyRunnable());
t.start();
t.join();
for(int i = 0; i < 100; i++) {
System.out.println("主线程" + i + ":齐姐666");
}
}
}

所以 join()
能够保证某个线程优先执行,而且会一直让它执行完,再回归到公平竞争状态。
join()
方法其实是用 wait()
来实现的,我们来看下这个方法。
2. wait() and notify()
wait()
其实并不是 Thread
类的方法,而是 Object
里面的方法。
该方法就是让当前对象等待,直到另一个对象调用 notify()
或者 notifyAll()
。
当然了,我们也可以设定一个等待时长,到时间之后对象将会自动苏醒。
4. yield()
yield
本身的中文意思是屈服,用在这里倒也合适。
yield()
表示当前线程主动让出 CPU 资源一下,然后我们再一起去抢。
注意这里让一下真的只是一下,从“执行中”回到“等待 CPU 分配资源”,然后所有线程再一起抢占资源。
5. sleep()
顾名思义,这个方法就是让当前线程睡一会,比如说,
myThread.sleep(1000); // 睡眠 1 秒钟
它会抛出一个 InterruptedException
异常,所以还要 try catch
一下。
6. currentThread()
Returns a reference to the currently executing thread object.
该方法是获取当前线程对象。
注意它是一个 static
方法,所以直接通过 Thread
类调用。
比如打印当前线程
System.out.println(Thread.currentThread());
前文的例子中,它会输出:
Thread[Thread-0,5,main]
Thread[main,5,main]
没错,它的返回值也是 Thread
类型。
7. getName()
该方法可以获取当前线程名称。
这个名称可以自己设置,比如:
Thread t = new Thread(new MyRunnable(), "壹齐学");
8. getId()
该方法是获取线程的 Id
.
9. getPriority()
线程也有优先级的哦~
虽然优先级高的线程并不能百分百保证一定会先执行,但它是有更大的概率被先执行的。
优先级的范围是 1-10
,我们来看源码:
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
如果不在这个范围,JDK 抛出 IllegalArgumentException()
的异常。
10. setPriority()
当然啦,我们也是可以自己设置某个线程的优先级的。
设置的优先级也需要在规定的 1-10
的范围内哦,如果不在这个范围也会抛异常。
11. stop()
最后我们来说下 stop()
方法,也是前文提到过的强制停止线程的一种方式,但现在已被弃用,因为会引起一些线程安全方面的问题。
好了,以上就是有关线程状态和常用 API 的介绍了。相信大家看完之后对线程的整个流程应该有了清晰的认识,其实里面还有很多细节我没有展开,毕竟这是多线程的第 2 讲,更深入的内容我们慢慢来。
如果你喜欢这篇文章,记得给我点赞留言哦~你们的支持和认可,就是我创作的最大动力,我们下篇文章见!
我是小齐,纽约程序媛,终生学习者,每天晚上 9 点,云自习室里不见不散!
更多干货文章见我的 Github: https://github.com/xiaoqi6666/NYCSDE
10 张图聊聊线程的生命周期和常用 APIs的更多相关文章
- Java 多线程(三)—— 线程的生命周期及方法
这篇博客介绍线程的生命周期. 线程是一个动态执行的过程,它也有从创建到死亡的过程. 线程的几种状态 在 Thread 类中,有一个枚举内部类: 上面的信息以图片表示如下: 第一张图: 第二张图:把等待 ...
- Java多线程学习(三)---线程的生命周期
线程生命周期 摘要: 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞 ...
- Java并发编程:线程的生命周期是个怎样的过程?
前言 在日常开发过程中,如果我们需要执行一些比较耗时的程序的话,一般来说都是开启一个新线程,把耗时的代码放在线程里,然后开启线程执行.但线程是会耗费系统资源的,如果有多个线程同时运行,互相之间抢占系统 ...
- JAVA面试题 线程的生命周期包括哪几个阶段?
面试官:您知道线程的生命周期包括哪几个阶段? 应聘者: 线程的生命周期包含5个阶段,包括:新建.就绪.运行.阻塞.销毁. 新建:就是刚使用new方法,new出来的线程: 就绪:就是调用的线程的star ...
- Java多线程之线程的生命周期
Java多线程之线程的生命周期 一.前言 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(R ...
- java线程的生命周期及五种基本状态
一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中的各知识点,Java中的多线程也就基本上掌 ...
- Java多线程 2 线程的生命周期和状态控制
一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...
- 第24章 java线程(3)-线程的生命周期
java线程(3)-线程的生命周期 1.两种生命周期流转图 ** 生命周期:**一个事物冲从出生的那一刻开始到最终死亡中间的过程 在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态 ...
- Java多线程——线程的生命周期和状态控制
一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...
随机推荐
- Python安装工具
1.官网下载地址是:https://www.python.org/downloads/ 默认下载安装时记得勾选配置PATH路径 PIP工具包(我是选择Python 3.5的) 2.Windows 下 ...
- 简单Web服务器
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.F ...
- 自己动手编写一个Mybatis插件:Mybatis脱敏插件
1. 前言 在日常开发中,身份证号.手机号.卡号.客户号等个人信息都需要进行数据脱敏.否则容易造成个人隐私泄露,客户资料泄露,给不法分子可乘之机.但是数据脱敏不是把敏感信息隐藏起来,而是看起来像真的一 ...
- LeetCode 873. 最长的斐波那契子序列的长度 题目详解
题目详情 如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的: n >= 3 对于所有 i + 2 <= n,都有 X_i + X_{i+1} = X_ ...
- 性能分析(6)- 如何迅速分析出系统 CPU 的瓶颈在哪里
性能分析小案例系列,可以通过下面链接查看哦 https://www.cnblogs.com/poloyy/category/1814570.html 前言 在做性能测试时,我们会需要对 Linux 系 ...
- ThinkPHP 6.0 基础教程 - 安装
ThinkPHP6.0 的环境: PHP >= 7.1.0 我本地环境: Win10 PhpStudy 安装 PhpStudy 如果你已经安装 PhpStudy 或其他环境,请忽略这里 安装方法 ...
- LeetCode 91,点赞和反对五五开,这题是好是坏由你来评判
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第57篇文章,我们一起来看看LeetCode第91题,解码方法(Decode ways). 这道题官方给定的难度 ...
- Uni-app从入门到实战
前言 uni-app是一个使用vue.js开发跨平台应用的前端框架,开发者只需要编写一套代码,便可以发布到IOS.Android和微信小程序等多个平台.所以我打算学习下这个框架,快速浏览了一遍官网之后 ...
- troubleshoot之:GC调优到底是什么
目录 简介 那些GC的默认值 GC的选择 GC的最大线程个数 初始化heap size 最大的heap size 分层编译技术 我们到底要什么 最大暂停时间 吞吐率 简介 我们经常会听到甚至需要自己动 ...
- Python-Opencv 图像处理基本操作
Python-Opencv 图像处理基本操作 1.图像读取 使用cv2.imread(filepath,flags)读入图像 filepath: 读入图像完整路径(绝对路径,相对路径) flags: ...