一个线程的生命周期有6个阶段:
- 新建,是刚使用new方法,new出来的线程;
- 就绪,是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段;
- 运行,当就绪的线程被调度并获得CPU资源时,便进入运行状态;
- 阻塞,在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态;
- 等待,线程进入等待状态是因为调用了wait()方法或者join()方法;
- 死亡,线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁。
线程的生命周期包含6个阶段,包括:新建、就绪、运行、阻塞、等待、死亡(销毁)。完整的生命周期图如下:
当线程进入运行状态后,一般的操作系统是采用抢占式的方式来让线程获得CPU。所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞、就绪之间切换。
使用new方法,new出来线程,此时仅仅由JAVA虚拟机为其分配内存,并初始化成员变量的值。此时仅仅是个对象。
就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
该线程进入就绪状态,JAVA虚拟机会为其创建方法调用栈和程序计数器。线程的执行是由底层平台控制, 具有一定的随机性。
当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;(当处于就绪状态的线程获得CPU,它就会执行run()方法)
对于一个单核cpu(或者是一个内核)来说,只能同时执行一条指令,而JVM通过快速切换线程执行指令来达到多线程的,真正处理器就能同时处理一条指令,只是这种切换速度很快,我们根本不会感知到。为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
当一个线程开始运行后,它不可能一直持有CPU(除非该线程执行体非常短,瞬间就执行结束了)。所以,线程在执行过程中需要被中断,目的是让其它线程获得执行的CPU的机会。线程的调度细节取决于底层平台所采用的策略。
处于运行中的线程,由于某种原因放弃对cpu的使用权,处于阻塞状态,直到其进入就绪状态,才有机会再次被cpu调用进入运行状态。
根据阻塞原因不同,阻塞分为三种
:
-
等待阻塞:运行状态中的线程执行wait方法,进入等待队列,等待阻塞;Java虚拟机就会把线程放到这个对象的等待池中
-
同步阻塞:线程获取同步锁失败(因为锁被其他线程占用),Java虚拟机就会把这个线程放到这个对象的锁池中
-
其他阻塞:通过调用sleep方法或者join方法或者发出I/O请求时,线程会进入阻塞状态,当sleep()状态超时,或者join()等待线程终止或者超时,或者I/O处理完毕,线程重新转入就绪状态
5、等待(Waiting)
线程进入等待状态是因为调用了wait()方法或者join()方法。在等待状态下,线程会暂停执行,直到其他线程调用notify()或者notifyAll()方法来唤醒它。
对于 Waiting
状态的进入有三种情况,分别为:
- 当线程中调用了没有设置
Timeout
参数的Object.wait()
方法 - 当线程调用了没有设置
Timeout
参数的Thread.join()
方法 - 当线程调用了
LockSupport.park()
方法
定时等待状态(TIMED_WAITING)
将运行状态中的线程转换为定时等待状态中的线程与转换为等待状态中的线程操作类似,只是运行线程调用了有时间参数限制的方法,如sleep(long millis)、wait(long timeout)、join(long millis)等方法。
处于定时等待状态中的线程也不能立即争夺CPU使用权,必须等待其他相关线程执行完特定的操作或者限时时间结束后,才有机会再次争夺CPU使用权,将定时等待状态的线程转换为运行状态。例如,调用了wait(long timeout) 方法而处于等待状态中的线程,需要通过其他线程调用notify()或者notifyAll()方法唤醒当前等待中的线程,或者等待限时时间结束后也可以进行状态转换。
6、销毁(terminated)
如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源。
- run()、call()方法执行完成,线程正常结束
- 线程抛出一个未捕获的Exception或Error
- 直接调用线程的stop()方法结束该线程——该方法容易导致死锁,通常不建议使用
线程状态转换图
总结
最后我们说一下再看线程转换的过程中一定要注意两点:
- 线程的状态是按照箭头方向来走的,比如线程从
New
状态是不可以直接进入Blocked
状态的,它需要先经历Runnable
状态。 - 线程生命周期不可逆:一旦进入
Runnable
状态就不能回到New
状态;一旦被终止就不可能再有任何状态的变化。 - 所以一个线程只能有一次
New
和Terminated
状态,只有处于中间状态才可以相互转换。也就是这两个状态不会参与相互转化