Java并发编程:线程的生命周期是个怎样的过程?

前言

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

线程的生命周期

线程的生命周期有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方法而导致意外死亡。

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

原文地址:https://www.cnblogs.com/yeya/p/10188688.html

时间: 2024-10-07 09:17:05

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

java并发编程线程安全

编写线程安全的代码实质就是管理对状态的访问,而且通常是共享的.可变的状态,对象的状态就是数据,存储在状态变量中,比如实例域,或者静态域,同时还包含了其它附属的域,例如hashmap的状态一部分存储到对象本身中,但同时也存储到很多mqp.entry中对象中,一个对象的状态还包含了任何会对他外部可见行为产生影响的数据. 所谓共享是指一个对象可以被多个线程访问, 所谓可变:是指变量的值在其生命周期内可以改变, 真正目的:在不可控制的并发访问中保护数据 线程安全必要条件: 1:对象是否被两个或以上的线程

Java中的线程的生命周期大体可分为5种状态

Java中的线程的生命周期大体可分为5种状态. ①NEW:这种情况指的是,通过New关键字创建了Thread类(或其子类)的对象 ②RUNNABLE:这种情况指的是Thread类的对象调用了start()方法,这时的线程就等待时间片轮转到自己这,以便获得CPU:第二种情况是线程在处于RUNNABLE状态时并没有运行完自己的run方法,时间片用完之后回到RUNNABLE状态:还有种情况就是处于BLOCKED状态的线程结束了当前的BLOCKED状态之后重新回到RUNNABLE状态. ③RUNNING

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

一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现Java.lang.IllegalThreadStateException异常. 2.就绪状态 处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它

JAVA 并发编程-线程同步通信技术(Lock和Condition)(十)

在之前的博客中已经介绍过线程同步通信技术<JAVA 并发编程-传统线程同步通信技术(四)>,上篇是使用的synchronized,wait,notify来实现,今天我们使用的是Lock和Condition,下面我们结合两者对比来学习. 简单的Lock锁应用: /** * 简单Lock的应用 * @author hejingyuan * */ public class LockTest { public static void main(String[] args) { new LockTest

JAVA 并发编程-线程同步工具类(十二)

本文主要介绍一些java线程同步工具类,并不进行具体讲解,当有需要时,可以再去结合实例学习. 信号灯(Semaphore) 应用场景举例: 例如公司的打卡系统,如果有一个打卡机,那么一次就只能有一个人打卡,其余的人就被阻塞住,打卡完以后就可由下一个人打卡.如果有3个打卡机,那么一次就允许3个人或者少于三个人打卡,其余的人就得等待打卡机空闲下来才能继续打卡. 结果: 已进入1个线程,还可进入2个 已进入2个线程,还可进入1个 已进入3个线程,还可进入0个 空余出1个 已进入4个线程,还可进入0个

Java并发编程——线程池的使用

在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPoolExecutor类中的方法讲起,

[Java并发编程]-线程的六种状态及其状态转换

转载请注明:http://blog.csdn.net/UniKylin/article/details/45050823 1.线程自身信息 线程运行的过程会产生很多信息,这些信息都保存在Thread类中的成员变量里面,常见的有: a.线程的ID是唯一标识getId() b.线程的名称:getName(),如果不设置线程名称默认为"Thread-xx" c.线程的优先级:getPriority,线程优先级从1-10,其中数字越大表示优先级别越高,同时获得JVM调度执行的可能性越大,JDK

Java并发编程——线程池

一.Java中的ThreadPoolExecutor类 二.深入剖析线程池实现原理 三.使用示例 四.如何合理配置线程池的大小 一.Java中的ThreadPoolExecutor类 java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类.下面我们来看一下ThreadPoolExecutor类的具体实现源码. 在ThreadPoolExecutor类中提供了四个构造方法: public c

JAVA 并发编程-线程与进程的由来(一)

在学习Java编程之初,我们就接触过Java线程,当时敲过代码也总结过,但是现在看来还是有点缺陷,并没有联系线程的由来来说明问题,只是简单的介绍了什么是进程,什么是线程,以及它们之间的关系-<Java-线程>.今天我们从进程和线程的由来来补充一下之前的总结. 参考:http://www.cnblogs.com/dolphin0520/p/3910667.html 一.操作系统中为什么会出现进程? 说起进程的由来,我们需要从操作系统的发展历史谈起. 最初计算机: 也许在今天,我们无法想象在很多年