Java多线程 - 线程的生命周期

Java多线程 - 线程的生命周期

引言:
Java线程被创建之后,并非是一启动就开始执行,也不是一直处于执行状态。
在线程的生命周期中,需要经过新建、就绪、运行、阻塞和死亡五种状态。
线程启动后,不可能一直占用着CPU独自运行,CPU需要再多条线程之间切换,于是线程状态也会多次在运行和就绪之间切换。

一、新建和就绪状态

当程序使用new关键字创建了一个线程之后,这个线程就会一直处于新建状态,此时它和Java对象一样,仅仅由Java虚拟机为其分配内存,并且初始化其成员变量的值,此时线程对象没有任何线程的动态特征,程序也不会执行线程的线程执行体。
当线程对象调用了start()方法之后,该线程就会处于就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器。处于这个状态的线程并没有开始运行,只是表示该线程可以运行了,至于该线程何时开始运行,这个取决于JVM里线程调度器的调度

注意:启动线程需要使用的是start()方法,而不是run()方法,永远不许调用线程对象的run()方法!
原因: 调用start()方法,来启动线程,会把该run()方法当成线程执行体来处理,但是如果说你要是直接调用了线程对象的run()方法,则run()方法立即就会别自行,而且,在run()方法之前的其他线程无法并发执行。也就是说:如果直接调用线程对象的run()方法,系统会把线程对象当做一个普通对象来进行处理,且run()方法也只是一个普通的方法了,并非是一个线程执行体。

class demo {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.run();

        MyThread thread2 = new MyThread();
        thread2.start();
    }
}

class MyThread extends Thread{

    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}

/*
运行结果:
main
Thread-1
由此可知,如果调用run方法,则知识当成一个普通的方法运行,其线程是main线程
 */

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

小知识: 如果你想让你创建的进程立刻开始运行,你可以使用Thread.sleep(1)来让当前运行的线程(主线程)睡眠1ms,1ms足够了,因为在这1ms内CPU并不会空闲,它回去执行另一个处于就绪状态的线程,这样子线程就开始立即执行。

二、运行和阻塞状态

如果处于就绪状态的线程获得了CPU, 开始执行run()方法的线程执行体,则该线程处于运行状态,如果说,计算机只有一个CPU,那么在任何时刻只有一个线程处于运行状态,当然,如果是一个多处理器的机器上,将会有多个线程并行,(注意:并行:同一时刻,有多条指令在多个处理器上同时执行。)当然,当线程数大于处理器数时,依然会有多个线程在同一CPU上轮换的现象。

当一个线程开始运行之后,不存在一直处于运行状态(当然,如果说线程执行体太短,瞬间完成, 那当我没说),线程在运行的过程中需要被中断,目的是为了使得别的线程获得一个执行的机会,线程调度的具体细节取决于底层平台所采用的的侧率。

目前,现代桌面和服务器操作系统均采用抢占式调度策略,但是有一些小型设备如同手机,可能采用协作式调度策略。

线程进入阻塞状态的可能原因:

  • 线程调用sleep()方法主动放弃所占用的处理器资源
  • 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程会一直被阻塞
  • 线程试图获得一个同步监视器,但是该同步监视器别的线程所拥有着
  • 线程在等待某个通知
  • 程序调用了线程的suspend()方法将该线程挂起(注意:该方法容易导致死锁)

当线程正在被执行的时候阻塞了,其他的线程就可以获得执行的机会,被阻塞的线程会在何时的时候重新进入就绪状态。
针对上面导致线程进入阻塞状态的可能原因,可以分析出,发生以下情况,则会解除上面的阻塞:

  • 调用sleep()方法的线程已经过了指定时间了
  • 线程调用的阻塞式IO方法已经返回
  • 线程成功地获得试图取得的同步监视器
  • 线程正在等待某个通知时,其他线程发出了一个通知
  • 处于挂起状态的线程调用了resume()修复方法

三、线程死亡

线程也会执行结束,当它执行结束的之后,就会处于死亡状态。
线程会以如下的方式结束:

  • run()call()方法执行完成,线程正常结束
  • 线程跑出一个未捕获的Exception或者Error
  • 直接调用该线程的stop()方法来结束该线程 – 该方法容易导致死锁,不推荐使用

注意:

  • 当主线程结束的时候,其他的线程不会受到任何影响,且不会随之结束,一旦子线程启动起来之后,他就会有与主线程一样的地位,不会受到主线程的影响
  • 不要试图对一个已经死亡的线程调用start()方法使它重新启动,死亡就是死亡了,就像恋爱被甩了,你还打算舔狗复合?!该线程已经不可以再次作为线程执行。不仅不要对死亡状态的线程调用start()方法,且程序只能够对新建的线程调用start()方法,当然,对新建状态的线程调用两次start()方法也是错误的,会引发IllegalThreadState异常。
  • 判断线程死亡:可以调用线程对象的isAlive()方法,当线程处于就绪,运行,阻塞三种状态的时候,返回true,如果处于新建和死亡两种状态,该方法就会返回false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章