当线程被创建并启动后,它既不是一启动就进入了执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New)、就绪(Ready)、运行(Running)、阻塞(Blocked)、和死亡(Dead)5种状态。
尤其是当线程启动以后,它不可能一直“霸占”着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行和就绪状态间切换。
使用new关键字创建了线程之后,该线程处于新建状态,此时线程对象不能运行, 和其他Java 对象一样, 仅仅由Java 虚拟机分配了内存, 并初始化成员变量的值。没有表现出任何线程的动态特征。程序不会执行线程的线程执行体(run方法内的内容)。
当线程对象调用了start() 方法后, 该线程即进入就绪状态, java虚拟机会为其创建方法调用栈和程序计数器,这个状态的线程并没有开始运行,只是表示该线程可运行了,此线程进入可运行池中, 等待CPU的资源。什么时候运行,取决于JVM的线程调度器的调度。
注意:启动线程用start() 而不是run(),直接调用run方法的话和调用普通方法一样。
处于就绪状态的线程获得CPU使用权后, 开始执行run() 方法中的线程执行体, 则该线程处于运行状态。
当计算机只有一个CPU时,任何时候只有一个线程在运行。当计算机有多个CPU时,将会有多个线程并行,若线程数大于CPU数时,依然存在多个线程在同一个CPU上轮换的现象。
当底层平台采用抢占式策略时,每一个线程都会获得一小段时间来处理任务,当时间用完后,会让出CPU让其他线程执行,在选择下一个线程时会考虑优先级。手机或一些小型设备采用协作式调度策略,一个线程会一直占用资源,只有调用了sleep()或yield()后才会放弃占用的资源,也就是必须主动放弃。
注意: 只有处于就绪状态的线程才可能进入运行状态。
正处于运行状态的线程遇到某些特殊情况时, 会放弃CPU使用权, 进入阻塞状态。当引起特殊情况的原因被解除后, 线程进入就绪状态, 回到可运行池中, 重新等待系统调度 的CPU使用权。
下面是从运行状态进入阻塞状态:
(1)线程调用了sleep()方法主动放弃所占用的处理器资源。
(2)线程调用了阻塞IO(write或read),在返回之前线程阻塞。
(3)线程调用同步监视器,若被其他线程持有,则阻塞。
(4)线程在等待某个通知notify()。
(5)程序调用了线程的suspend()方法挂起。该方法会造成死锁,尽量避免。
下面是从阻塞状态进入就绪状态:
(1)调用sleep的方法的线程经过了指定时间。
(2)阻塞IO方法返回。
(3)取得同步监视器。
(4)线程在等待某个通知,其他线程发出通知。
(5)挂起状态的线程被调用了resume()恢复方法。
下面三种方法,线程会进入四忙状态:
(1)当run() 或call()方法执行完毕,线程政策结束。
(2)线程抛出一个未捕获的异常 或者 错误的时候(Exception或Error)。
(3)直接调用线程stop()方法,不建议,会造成死锁。
进入死亡状态的线程不再拥有运行的资格, 也不能转换到其他状态。
不要试图对死亡的线程调用start,只有新建状态才能调用start().
新建状态的线程调用两次start()也会报IllegalThreadStateException错误。