前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >新手学JAVA(十一)-多线程----线程的生命周期

新手学JAVA(十一)-多线程----线程的生命周期

作者头像
令仔很忙
发布2018-09-14 16:36:21
3940
发布2018-09-14 16:36:21
举报
文章被收录于专栏:令仔很忙令仔很忙

当一个线程被创建并启动之后,并不是一开始就处于执行状态,已不是一直处于运行状态。线程也是有生命周期的,包括:创建(New)、就绪(Runnable)、阻塞(Blocked)、运行(Running)、死亡(Dead)五种状态。当线程运行时,也不可能一直霸占着CPU独自运行,而是一直在运行、就绪状态之间切换。

新建和就绪状态


当程序通过new创建一个线程时,这个线程就处于新建(New)状态了,不过这个时候该线程并没有表现出线程的任何特征,和其他的普通java对象一样,java虚拟机为其分配内存,并初始化其变量的值。

当线程对象调用了start()方法之后,该线程就进入了就绪状态,此时还不是运行状态,java虚拟机为其创建方法调用栈和程序计数器,此时的线程表示可以运行了,但是具体什么时候运行,还需要等待jvm的调度。

有一个需要注意的地方,启动一个线程需要调用的是start()方法,而不是用run()来启动线程,如果直接调用run方法的话,系统会把线程当成一个普通的对象,run()方法也只是一个普通的方法。给大家举个栗子:

代码语言:javascript
复制
package lifecycle;

public class InvokeRun extends Thread{
    private int i;

    public void run(){
        for(;i<100;i++){
            System.out.println(Thread.currentThread().getName() + " " +i);
        }
    }

    public static void main(String[] args){
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + " " +i);
            if(i==20){
                new InvokeRun().run();
                new InvokeRun().run();
            }
        }
    }
}

当启动线程的时候直接用run()方法,最终的结果是:整个程序的运行只有一个线程。程序编程了单线程的了。主要是因为,当你启动线程的时候,如果调用的start()方法,系统会把run()方法当成线程的执行体。直接调用run()方法的话,在run()方法返回之前其他线程无法并发运行。

只能对处于新建状态的线程调用start()方法,否则将引发IllegalThreadStateException异常

运行状态和阻塞状态


当一个就绪的线程获得CPU之后,就进入了运行状态,系统如果只有一个CPU的话,就会出现多个线程在同一个CPU上轮换的现象,一个CPU在任何时间只有一个线程在运行。如果有多个CPU的话,就会出现多个线程并行(parallel)执行; 一个线程不可能一直处于运行状态,除非这个线程在足够短的时间内就能执行完成,否则的话,线程在执行的过程中都会被中断数次,目的是为了给其他的线程执行的机会,具体的需要考虑后台的执行策略。

这里写图片描述
这里写图片描述

上图是线程的状态转换图,通过上图我们就可以了解到,线程是在什么条件下进入到阻塞(Blocked)状态,又在什么条件下进入到就绪(Runnable)状态;通过上图还可以了解到一点,线程并不是直接从运行状态转到就绪状态的,除了yield()方法。

线程死亡


线程会以下面三种方式结束,结束后就是死亡状态。

  1. run()call()方法执行完成,线程正常结束。
  2. 线程抛出一个未捕获的ExceptionError
  3. 直接调用该线程的stop()方法来结束该线程—-该方法通常容易导致死锁,不推荐使用。

当线程死亡之后,其他的线程并不受其影响,而结束。其他的子线程启动之后,它的地位和主线程是等同的,不受主线程的影响。

如何测试一个线程是否已经死亡?用线程对象的isAlive()方法来测,当线程处于就绪、运行、阻塞状态时,返回的结果是true,当线程处于死亡、新建状态时返回的是false。下面举一个对已死的线程调用start()方法的例子:

代码语言:javascript
复制
package startDead;

public class StartDead extends Thread {

    private int i;

    public void run(){
        for(;i<100;i++){
            System.out.println(getName()+" "+i);
        }
    }
    /**
     * @param args
     */
    public static void main(String[] args) {

        StartDead sd =new StartDead();
        for(int i=0;i<300;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20){
                sd.start();
                System.out.println(sd.isAlive());
            }
            //当i>20的时候,线程肯定已经启动过了,如果sd.isAlive()为假时,那就是死亡状态了;
            if(i>20 && !sd.isAlive()){
                //试图再次启动线程
                sd.start();
            }
        }


    }

}

对已经死亡的线程调用start()方法,会抛出IllegalThreadStateException异常。

代码语言:javascript
复制
Exception in thread "main" java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:595)
    at startDead.StartDead.main(StartDead.java:27)

不要试图对已经死亡的线程调用start()方法,死亡就是死亡,死亡的线程不会再次被当成线程的执行体。程序只能对处于新建状态的线程调用start()方法,对处于新建状态的线程两次调用start()也是错误的,这都会引发IllegalThreadStateException异常

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年06月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 新建和就绪状态
  • 运行状态和阻塞状态
  • 线程死亡
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档