• java并发编程-线程生命周期


    线程生命周期

    现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。

    CPU再切换线程是会导致线程存在各种状态,线程从创建到死亡其中存在不同的生命状态;本文将对线程生命周期进行全面的介绍。

    Java线程的状态可以从java.lang.Thread的内部枚举类java.lang.Thread$State得知:

    public enum State {
          
        NEW,
    
        RUNNABLE,
    
        BLOCKED,
    
        WAITING,
    
        TIMED_WAITING,
    
        TERMINATED;
    }

    当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过 新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked、WATING、TIMED_WATING)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自运行,所以CPU需要在多条线程之间切换,于是 线程状态也会多次在运行、阻塞之间切换

    • 新建状态(New)

      API注释: 

      /**
       * Thread state for a thread which has not yet started. 
       * 线程实例尚未启动时候的线程状态
       */
      NEW,

      当线程对象创建后,即进入新建状态,如:Thread t = new MyThread();

    • 就绪状态(Runnable)

      API注释

      /**
       * Thread state for a runnable thread.  A thread in the runnable
       * state is executing in the Java virtual machine but it may
       * be waiting for other resources from the operating system
       * such as processor.
       */
      RUNNABLE,
      
      可运行状态下线程的线程状态。可运行状态下的线程在Java虚拟机中执行,但它可能执行等待操作系统的其他资源,例如处理器。

      当调用线程对象的start()方法时,线程即进入就绪状态。处于就绪状态的线程只是说明此线程已经做好准备,随时等待CPU调度执行,并不是说执行了start()方法就立即执行。

      当Java线程实例调用了Thread#start()之后,就会进入RUNNABLE状态。RUNNABLE状态可以认为包含两个子状态:READYRUNNING

      • READY:该状态的线程可以被线程调度器进行调度使之更变为RUNNING状态。
      • RUNNING:该状态表示线程正在运行,线程对象的run()方法中的代码所对应的的指令正在被CPU执行。
      • 当Java线程实例Thread#yield()方法被调用时或者由于线程调度器的调度,线程实例的状态有可能由RUNNING转变为READY,但是从线程状态Thread#getState()获取到的状态依然是RUNNABLE。例如:
      • public class ThreadState1 {
        
            public static void main(String[] args) throws Exception {
                Thread thread = new Thread(()-> {
                    while (true){
                        Thread.yield();
                    }
                });
                thread.start();
                Thread.sleep(2000);
                System.out.println(thread.getState());
            }
        }
        // 输出结果
        RUNNABLE
    • 运行状态(Running)

      当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。

    • WATING状态

             WAITING无限期的等待状态,这种状态下的线程不会被分配CPU执行时间。当一个线程执行了某些方法之后就会进入无限期等待状态,直到被显式唤醒,被唤醒后,线程状态由WAITING更变为RUNNABLE然后继续执行。

    • TIMED WATING状态

             TIMED WAITING就是有限期等待状态,它和WAITING有点相似,这种状态下的线程不会被分配CPU执行时间,不过这种状态下的线程不需要被显式唤醒,只需要等待超时限期到达就会被VM唤醒,有点类似于现实生活中的闹钟。

     
    • 阻塞状态(Blocked)

    处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。

    阻塞状态分类

    1. 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    2. 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程占用),它会进入到同步阻塞状态;
    3. 其他阻塞:通过调用线程的sleep()或join()或发出I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
    • 死亡状态

      线程执行完毕或者是异常退出,该线程结束生命周期。

    线程相关方法
     

    public class Thread{
        // 线程的启动
        public void start(); 
        // 线程体
        public void run(); 
        // 已废弃
        public void stop(); 
        // 已废弃
        public void resume(); 
        // 已废弃
        public void suspend(); 
        // 在指定的毫秒数内让当前正在执行的线程休眠
        public static void sleep(long millis); 
        // 同上,增加了纳秒参数
        public static void sleep(long millis, int nanos); 
        // 测试线程是否处于活动状态
        public boolean isAlive(); 
        // 中断线程 - 进入阻塞状态
        public void interrupt(); 
        // 测试线程是否已经中断
        public boolean isInterrupted(); 
        // 测试当前线程是否已经中断
        public static boolean interrupted(); 
        // 等待该线程终止
        public void join() throws InterruptedException; 
        // 等待该线程终止的时间最长为 millis 毫秒
        public void join(long millis) throws InterruptedException; 
        // 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
        public void join(long millis, int nanos) throws InterruptedException; 
    }
    

    笔者的微信公众号,每天一篇好文章:

  • 相关阅读:
    【解题报告】NOIP2018
    【解题报告】NOIP2013
    【解题报告】NOIP2014
    【解题报告】NOIP2015
    【解题报告】NOIP2016
    【解题报告】CSPS2020
    【全程NOIP计划】初级数据结构1
    如何通过一个结构体成员变量的地址找到该结构体的首地址?[备忘]
    IGT笔试题,正整数N等于M个不同的正整数之和的问题
    Mac下Perl脚本如何运行
  • 原文地址:https://www.cnblogs.com/coder306/p/13087595.html
Copyright © 2020-2023  润新知