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方法进入就 ...
随机推荐
- 【LeetCode/LintCode 题解】约瑟夫问题 · Joseph Problem
n个人按顺序围成一圈(编号为1~n),从第1个人从1开始报数,报到k的人出列,相邻的下个人重新从1开始报数,报到k的人出列,重复这个过程,直到队伍中只有1个人为止,这就是约瑟夫问题.现在给定n和k,你 ...
- python3.x与2.x中print输出不换行
python3.x: print(i,end=' ') 循环输出: ... ------------------------- print(i,end='!') 循环输出:!!!... end=单引号 ...
- C#LeetCode刷题之#641-设计循环双端队列(Design Circular Deque)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4132 访问. 设计实现双端队列. 你的实现需要支持以下操作: M ...
- 【深度学习】:一门入门3D计算机视觉
一.导论 目前深度学习已经在2D计算机视觉领域取得了非凡的成果,比如使用一张图像进行目标检测,语义分割,对视频当中的物体进行目标跟踪等任务都有非常不错的效果.传统的3D计算机视觉则是基于纯立体几何来实 ...
- JavaScript在HTML中的基础用法总结
网页主要由三部分组成,分别为html.CSS和Javascript.如果说HTML是肉身,CSS是皮相,那Javascript就是灵魂.因此,三者的联系与融合则至关重要.本文就来为大家讲解一下Java ...
- 虚拟机解释器与bytecode对接
心头一直有个疑问,jvm虚拟是如何对接class中的字节码的?或者说在未进入 JIT优化阶段时,解释器是如何对接的? 大概阐述 hotspot通过C++代码在堆上申请一块空间,向里面填充一组指令,然后 ...
- Disruptor极速队列
参考:http://www.cnblogs.com/haiq/p/4112689.html Disruptor 是线程内通信框架,用于线程里共享数据.LMAX 创建Disruptor作为可靠消息架构的 ...
- 【期外】 (一)关于LSH :局部敏感哈希算法
LSH是我同学的名字,平时我会亲切的称呼他为离骚,老师好,左移(leftshift),小骚骚之类的,最近他又多了一个新的外号:局部敏感哈希(Locally sensitive hashing). 好了 ...
- 源码解析JDK1.8-HashMap链表成环的问题解决方案
前言 上篇文章详解介绍了HashMap在JDK1.7版本中链表成环的原因,今天介绍下JDK1.8针对HashMap线程安全问题的解决方案. jdk1.8 扩容源码解析 public class Has ...
- 推荐一款万能抓包神器:Fiddler Everywhere
搞IT技术的同行,相信没有几个人是不会抓包这项技能的(如果很不幸你中枪了,那希望这篇文章给你一些动力),市面上的抓包工具也有很多,常用的有:Charles.Fiddler.Burpsuite.Wire ...