前言

在日常开发过程中,如果我们需要执行一些比较耗时的程序的话,一般来说都是开启一个新线程,把耗时的代码放在线程里,然后开启线程执行。但线程是会耗费系统资源的,如果有多个线程同时运行,互相之间抢占系统资源,那无疑会对系统造成极大的压力。所以,怎么操作线程,保证不影响整个应用功能是很重要的,而这就需要我们了解线程的生命周期了。

线程的生命周期

线程的生命周期有6种状态,分别是NEW(新建)、RUNNABLE(可运行)、BLOCKED(被阻塞)、 WAITING(等待)、TIMED_WAITING(计时等待)、TERMINATED(被终止),在 Thread 源码的 State 枚举中都有定义:

public static enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED; private State() {
}
}

1、NEW 状态表示刚刚创建的线程,此时的线程还没运行,也就是还没执行start() 方法,创建线程的方式也比较简单,可以参考《Java并发编程:Java创建线程的三种方式》

2、当线程执行时,处于 RUNNABLE 状态,表示线程所需的资源已经准备好了。

3、如果线程在执行的过程中遇到被阻塞的情况,例如线程中的程序中有synchronized 同步代码块,线程就会暂停执行,进入阻塞状态,直至获取请求的锁,这时线程就处于 BLOCKED 状态。

实例代码如下:

public class ThreadDemo {

    public static Object testObject = new Object();

    public static class MyThread extends Thread {

        public MyThread(String name) {
super.setName(name);
} @Override
public void run() {
//每次跑run方法都需要获取testObject对象
synchronized (testObject) {
System.out.println("thread name:" + this.getName()); //..............耗时操作..............
}
} } public static void main(String[] args) {
for (int i = 1; i <= 100; i++) {
new MyThread("线程"+i).start();
}
}
}

在上面的代码中,线程的run方法在执行耗时的程序之前都需要先获取testobject对象的锁,因为对象锁是公共对象,所以,多个线程同时运行时,同一时刻只能有一个线程获取锁,假设某个时刻是 A线程 获取了锁,其他线程就会处于等待锁释放的阻塞状态,直到获取锁才能继续执行程序,这就是线程的BLOCKED 状态。

4、WAITING 表示等待的状态,处于 WAITING 状态的线程会进入一个无时间限制的等待,一旦等到了期望的事件,线程就会再次执行,进入RUNNABLE 状态。最典型的场景就是 等待(wait)通知(notify)

等待状态对应的方法是wait(),而通知是notify(),这两个方法并不属于Thread类,而是属于Object类,所以所有对象都可以使用这两个方法。当一个对象实例 obj 调用 wait() 方法后,当前线程就会在这个对象上等待,直到其他线程调用 obj.notify() 为止。这时的对象实例 obj 就相当于多个线程之间的通信工具。实例代码如下:

public class ThreadDemo {

    public static Object testObject = new Object();

    public static class MyThread1 extends Thread {
@Override
public void run() {
synchronized (testObject) {
System.out.println("MyThread1 wait :" + System.currentTimeMillis());
try {
//调用wait方法进入等待状态
testObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public static class MyThread2 extends Thread {
@Override
public void run() { synchronized (testObject) {
System.out.println("MyThread2 start notify :" + System.currentTimeMillis());
//..............耗时操作.............. //发出通知,唤醒等待的线程
testObject.notify();
}
}
} public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.start();
t2.start();
}
}

5、TIMED_WAITINGWAITING 一样,都表示等待状态,但TIMED_WAITING 会进行一个 有时限的等待。操作线程状态有几个方法是带有超时参数的,调用方法的线程进入计时等待状态。这一状态将一直保持到超时期满或者接收到适当的通知,最常见的应用就是调用 Thread.sleep() 方法。

实例代码如下:

public static class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread start :" + System.currentTimeMillis());
try {
//休眠两秒钟
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThread end :" + System.currentTimeMillis());
}
}
public static void main(String[] args) {
MyThread t = new MyThread1();
t.start();
}

启动线程后,程序运行到 Thread.sleep() 方法会处于休眠状态,时间根据参数来决定,单位是毫秒,所以执行main方法后,后一条输出内容会隔两秒钟出现。

MyThread start :1544704974271
MyThread end :1544704976272

6、当线程执行完毕后,进入 TERMINATED 状态,表示结束,一般线程被终止有两种原因:

  • run方法正常运行后就自然消亡。

  • 因为一个没有捕获的异常终止了run方法而导致意外死亡。

好了,线程的生命周期就总结完了,用一张图表示大概是这样:

Java并发编程:线程的生命周期是个怎样的过程?的更多相关文章

  1. Java多线程之线程的生命周期

    Java多线程之线程的生命周期 一.前言 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(R ...

  2. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  3. java并发编程 线程基础

    java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...

  4. java并发编程-线程生命周期

    线程生命周期 现代操作系统在运行一个程序时,会为其创建一个进程.例如,启动一个Java程序,操作系统就会创建一个Java进程.现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight ...

  5. Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗

    在上一章,为大家介绍了线程的一些基础知识,线程的创建与终止.本期将为各位带来线程的生命周期与常用方法.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程生命周期 一个线程不是被创建了 ...

  6. java并发编程 | 线程详解

    个人网站:https://chenmingyu.top/concurrent-thread/ 进程与线程 进程:操作系统在运行一个程序的时候就会为其创建一个进程(比如一个java程序),进程是资源分配 ...

  7. Java多线程 2 线程的生命周期和状态控制

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...

  8. Java并发编程:线程间通信wait、notify

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  9. Java并发编程:线程和进程的创建(转)

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

随机推荐

  1. python运算符优先级

    下面这个表给出Python的运算符优先级,从最低的优先级(最松散地结合)到最高的优先级(最紧密地结合).这意味着在一个表达式中,Python会首先计算表中较下面的运算符,然后在计算列在表上部的运算符. ...

  2. shell脚本学习- 传递参数

    跟着RUNOOB网站的教程学习的笔记 我们可以在执行shell脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n代表一个数字,1为执行脚本的第一参数,2为执行脚本的第二个参数,以此类推... 实 ...

  3. Codeforces Round #536 (Div. 2)--1106D - Lunar New Year and a Wander

    https://codeforces.com/contest/1106/problem/D 题意:求出字典序最小的走法 解法:走到每个点,都选取与这个点连通的序号最小的点,并且这个序号最小的点没有被访 ...

  4. 前端vue框架 路由的安装及使用

    安装: 1.cmd下输入: npm install vue-router --save //安装路由 2.npm run dev //重新启动 使用: 1.在mian.js下引入路由 import V ...

  5. iOS逆向之TheOS

    TheOS 被设计为一个在基于 Unix 平台 (Mac OS X.IOS…) 和大多数 的Linux 平台下开发 iOS 程序的集成开发环境.说是集成开发环境,其实就是给我们准备好了一些代码模板.预 ...

  6. Android OpenGL ES 开发(N): OpenGL ES 2.0 机型兼容问题整理

    在使用OpenGL ES做开发的时候,发现不是所有机型对OpenGL的代码都兼容的那么好,同样的代码在某些机型上总是会出现问题,但是在其他手机上就是好的.下面是本人总结的OpengGL 兼容问题: 一 ...

  7. vscode 集成 cygwin 的注意事项

    vscode 集成 cygwin vscode 现在是我的主力开发编辑器,它自带 terminal 不需要我各种切换,我还想要在 windows 下执行一些简单的 .sh 文件.所以,我希望有一款工具 ...

  8. nginx反向代理转发apache配置 之 cookie去哪儿了?

    在公司接手了个微信项目,由于微信环境下访问网站需要使用对外开放的域名,所以有相关问题,都是直接运维同事帮忙处理. 原理是这样: 方案一: 1. 将域名解析指向测试服务器的地址: 2. 开放相关端口访问 ...

  9. python多进程没有锁队列范例

    假设有一些任务要完成.为了完成这项任务,将使用几个过程.所以,将保持两个队列.一个包含任务,另一个包含已完成任务的日志. 然后实例化流程来完成任务.请注意,python队列类已经同步. 这意味着,我们 ...

  10. [原创]MOF提权下载者代码

    0x001 网上的mof提权 调用的是js执行添加用户 而且有个缺陷 还不能一步到位...目标3389也连不上...也不知道上面安装了什么软件...毛然添加用户也不好比如有个类似狗之类的拦截添加用户 ...