JAVA进阶系列 - 并发编程 - 第3篇 线程的生命周期
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JAVA进阶系列 - 并发编程 - 第3篇 线程的生命周期,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6553字,纯文字阅读大概需要10分钟。
内容图文
![JAVA进阶系列 - 并发编程 - 第3篇 线程的生命周期](/upload/InfoBanner/zyjiaocheng/612/1744cdab117449f39f52c712ed6645a3.jpg)
目标
-
线程的生命周期
-
线程的状态定义
-
线程的状态转移
内容
1. 线程的生命周期说明
上一篇文章中,我们简单的描述了同步与异步的差异以及线程的基本使用。那么今天我们就来了解一下线程的生命周期。
在调用了 Thread 类对象的 start 方法来启动 Java 线程后,对应的底层操作系统线程不能马上得到 CPU 时间片来执行,需要等待操作系统的调度。所以,为了便于跟踪 Java 线程的执行情况,Thread 类定义了一系列的线程状态来表示当前线程的执行情况,同时整个线程的整个生命周期就是在这些状态直接转换。
2. 线程的状态定义
为了便于对 Java 的线程进行管理和对线程的运行情况进行跟踪,Java 定义了 6 个线程状态来表示线程的当前运行情况,这6个状态具体在 Thread 类的内部枚举类 State 中定义:
public?enum?State?{
????//?新建状态
????NEW,
????//?可运行状态
????RUNNABLE,
????//?阻塞状态
????BLOCKED,
????//?等待状态
????WAITING,
????//?超时等待状态
????TIMED_WAITING,
????//?终止状态
????TERMINATED;
}
2.1. 新建状态 NEW
当我们用关键字 new 创建一个 Thread 对象时,因为没有调用 start 方法启动该线程,此时的 Thread 对象就是一个普通的 Java 对象,并不会执行任何操作。
@Slf4j
public?class?ThreadStateDemo?{
????public?static?void?main(String[]?args)?{
????????Thread?t1?=?new?Thread(()?->?{
????????????log.debug("running...");
????????},?"t1");
????????log.debug("t1?state?{}",?t1.getState());????//?t1?state?NEW
????}
}
2.2. 可运行状态 RUNNABLE
线程通过调用 start 方法启动,使该线程对象进入 RUNNABLE 状态,此时才真正地在 JVM 进程中创建了一个线程。
但是线程启动之后可以立即得到执行吗?答案是否定的。线程的运行与否和进程一样都要听命于 CPU 的调度。如果操作系统的 CPU 此时是空闲的,则该线程对象对应的线程可以立即获取到 CPU 时间片并执行(此时的线程状态为运行中running)。反之,如果此时 CPU 繁忙,不能马上分配 CPU 时间片资源来执行该线程,则该线程需要等待操作系统之后的调度来获得 CPU 时间片并执行(此时的线程状态为就绪ready)。
@Slf4j
public?class?ThreadStateDemo?{
????public?static?void?main(String[]?args)?{
????????Thread?t2?=?new?Thread(()?->?{
????????????while(true){
????????????????//?runnable
????????????}
????????},?"t2");
????????t2.start();
????????log.debug("t2?state?{}",?t2.getState());????//?t2?state?RUNNABLE
????}
}
#### 2.3\. 阻塞状态 BLOCKED
当线程处于阻塞状态 BLOCKED 时,线程不能继续往下执行。这种情况主要出现在如下几种情况中:
-
调用了 sleep 或者 wait 方法而加入了 waitSet 中;
-
进行某个阻塞的 IO 操作;
-
获取某个锁资源失败从而加入到该锁的阻塞队列中;
@Slf4j
public?class?ThreadStateDemo?{
????public?static?void?main(String[]?args)?{
????????Thread?t5?=?new?Thread(()?->?{
????????????synchronized?(ThreadStateDemo.class)?{
????????????????try?{
????????????????????//?time_waiting
????????????????????Thread.sleep(1000000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????},?"t5");
????????t5.start();
????????Thread?t3?=?new?Thread(()?->?{
????????????//?t5?线程先占用锁,所以该线程会进入?blocked?状态
????????????synchronized?(ThreadStateDemo.class)?{
????????????????try?{
????????????????????Thread.sleep(1000000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????},?"t3");
????????t3.start();
????????log.debug("t3?state?{}",?t3.getState());????//?t3?state?BLOCKED
????}
}
#### 2.4\. 等待状态 WAITING
线程处于等待状态 WAITING 主要出现在与其他线程进行协作的场景中,具体为当前线程等待其他线程执行某种操作来通知和唤醒当前线程。当前线程处于等待状态 WAITING 时,除了不能继续往下执行外,还有个特性是如果当前线程持有锁,如在 synchronized 方法内或者 synchronized 同步代码块内部执行时,线程进入了等待状态,则会自动释放锁,这样其他线程可以竞争获取该锁。
在 Thread 类的方法设计中,主要是基于 Object 类的 wait、notify 和 notifyAll 方法实现的,其中线程调用 wait 方法时,进入等待状态。另外当线程调用 Thread 类的 join 方法或者调用 LockSupport 的静态 park 方法时,线程也会进入等待状态 WAITING。
@Slf4j
public?class?ThreadStateDemo?{
????public?static?void?main(String[]?args)?{
????????Thread?t2?=?new?Thread(()?->?{
????????????while(true){
????????????????//?runnable
????????????}
????????},?"t2");
????????t2.start();
????????Thread?t4?=?new?Thread(()?->?{
????????????try?{
????????????????//?waiting
????????????????t2.join();
????????????}?catch?(InterruptedException?e)?{
????????????????e.printStackTrace();
????????????}
????????},?"t4");
????????t4.start();
????????log.debug("t4?state?{}",?t4.getState());????//?t4?state?WAITING
????}
}
#### 2.5\. 超时等待状态 TIMED_WAITING
超时等待状态 TIMED_WAITING 与等待状态 WAITING 功能类似,不同之处在于 WAITING 状态的等待不支持指定等待时间,没有超时机制,一旦条件不满足就会无限等待下去。而处于超时等待状态 TIMED_WAITING 的线程,指定了最长等待时间,如果超过这个时间条件还未满足,则当前线程会自动唤醒并继续往下执行。
@Slf4j
public?class?ThreadStateDemo?{
????public?static?void?main(String[]?args)?{
????????Thread?t5?=?new?Thread(()?->?{
????????????synchronized?(ThreadStateDemo.class)?{
????????????????try?{
????????????????????//?time_waiting
????????????????????Thread.sleep(1000000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????},?"t5");
????????t5.start();
????????log.debug("t5?state?{}",?t5.getState());????//?t5?state?TIMED_WAITING
????}
}
#### 2.6\. 终止状态 TERMINATED
TERMINATED 是一个线程的最终状态。当 Thread 线程对象对应的现场执行完毕时,线程进入终止状态 TERMINATED,在该状态中线程将不会切换到其他任何状态。这意味着该线程整个生命周期都结束了,对应的 Thread 类对象也会被回收销毁。下列这些情况都将会使线程进入 TERMINATED 状态:
-
线程正常运行结束;
-
线程意外出错结束;
-
JVM Crash,导致所有线程结束;
@Slf4j
public?class?ThreadStateDemo?{
????public?static?void?main(String[]?args)?{
????????Thread?t6?=?new?Thread(()?->?{
????????????log.debug("running...");
????????},?"t6");
????????t6.start();
????????try?{
????????????//?这里主线程休眠一下,让
????????????Thread.sleep(500);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????log.debug("t6?state?{}",?t6.getState());????//?t6?state?TERMINATED
????}
}
### 3\. 线程的状态转换
图片来源:B站 - 黑马程序员
上图中箭头表示可由该状态向对应状态转换。其中,RUNNABLE 状态涵盖了操作系统层面的 【可运行状态】【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在Java里面无法区分,仍然认为是可运行)
总结
本篇我们学习了线程的生命周期,在使用多线程的过程中,线程的生命周期将会贯穿始终,只有清晰地掌握生命周期各个阶段的切换,才能更好地理解线程的阻塞以及唤醒机制,同时也为掌握同步锁等概念打下一个良好的基础。
今天的文章到这里就结束了,小伙伴们有什么建议或者意见请联系我改进哦,微信公众号:【该昵称无法识别】,你们的支持是我最大的动力!!!
内容总结
以上是互联网集市为您收集整理的JAVA进阶系列 - 并发编程 - 第3篇 线程的生命周期全部内容,希望文章能够帮你解决JAVA进阶系列 - 并发编程 - 第3篇 线程的生命周期所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。