1.线程的生命周期
通过图1-2的展示可知,线程的生命周期大体可以分为如下5个主要的阶段。
- NEW
- RUNNABLE
- RUNNING
- BLOCKED
- TERMINATED
1)线程的NEW状态
当我们用关键字new创建一个Thread对象时, 此时它并不处于执行状态, 因为没有调
用start方法启动该线程, 那么线程的状态为NEW状态, 准确地说, 它只是Thread对象的
状态, 因为在没有start之前, 该线程根本不存在, 与你用关键字new创建一个普通的Java
对象没什么区别。
NEW状态通过start方法进人RUNNABLE状态
2)线程的RUNNABLE状态
线程对象进入RUNNABLE状态必须调用start方法, 那么此时才是真正地在JVM进程中创建了一个线程,线程一经启动就可以立即得到执行吗?答案是否定的,线程的运行与否和进程一样都要听令于CPU的调度那么我们把这个中间状态称为可执行状态(RUNNABLE) , 也就是说它具备执行的资格但是并没有真正地执行起来而是在等待CPU的调度。
由于存在Running状态, 所以不会直接进入BLOCKED状态和TERMINATED状态, 即使是在线程的执行逻辑中调用wait、 sleep或者其他block的IO操作等, 也必须先获得CPU的调度执行权才可以, 严格来讲,RUNNABLE的线程只能意外终止或者进入RUNNING状态。
3)线程的RUNNING状态
一旦CPU通过轮询或者其他方式从任务可执行队列中选中了线程, 那么此时它才能真正地执行自己的逻辑代码, 需要说明的一点是一个正在RUNNING状态的线程事实上也是RUNNABLE的, 但是反过来则不成立。在该状态中,线程的状态可以发生如下的状态转换。
- 直接进入TERMINATED状态, 比如调用JDK已经不推荐使用的stop方法或者判断某个逻辑标识。
- 进入BLOCKED状态, 比如调用了sleep, 或者wait方法而加人了wait Set中。
- 进行某个阻塞的IO操作, 比如因网络数据的读写而进入了BLOCKED状态。
- 获取某个锁资源, 从而加入到该锁的阻塞队列中而进入了BLOCKED状态。
- 由于CPU的调度器轮询使该线程放弃执行, 进入RUNNABLE状态。
- 线程主动调用yield方法, 放弃CPU执行权, 进入RUNNABLE状态。
2.重写Thread的run方法与实现Runnable接口的run方法的区别?
重写Thread类的run方法和实现Runnable接口的run方法还有一个很重要的不同,那就是Thread类的run方法是不能共享的, 也就是说A线程不能把B线程的run方法当作自己的执行单元, 而使用Runnable接口则很容易就能实现这一点, 使用同一个Runnable的实例构造不同的Thread实例。