一、通用的线程生命周期:“五态模型”
二、java线程有哪几种状态?
- New:创建完线程
- Runable:start(),这里的Runnable包含操作的系统的Running(运行状态)和Ready(上面的可运行状态)
- Blocked:等待一个排它锁,当java线程在调用阻塞api时(阻塞读取文件),是否会转到Blocked那?在jvm层面,java线程状态是不会发生变化,还是Runnable,因为jvm不关心操作系统调度,在jvm看来,等待cpu使用权(操作系统层面处于可运行状态)和等待i/o(操作系统此时处于休眠状态)没有区别,都是在等待某个资源,所以都归于Runnable状态。只有在等待获取隐式锁的时候,才会进入到阻塞状态。
- Waiting(无限期等待):等待其他线程显示的唤醒,否则不会被分配cpu时间片
- Time Waiting(限期等待):无需等待其他线程显式的唤醒,在一定时间之后会被系统自动唤醒
调用Thread.sleep方法会使得线程进入限期等待状态,常常用“使一个线程睡眠”描述
调用object.wait(xxx) 方法使得线程进入限期等待,常常用“挂起一个线程”描述
睡眠和挂起是一个动作,阻塞和等待是一个状态
阻塞和等待的区别在于,阻塞是一个被动的,它是在等待一个排它锁;等待(无论来自于sleep还是wait)是一个主动的,通过主动调用方法进入的
- Terminated: 1、线程正常执行完 2、线程被interrupt(这里是不建议使用stop的,如果用stop杀死线程的话,如果线程持有Lock锁,就不会调用unlock也就不会释放锁)。
另外:
Blocking、Waiting、Timed_Waiting这几种状态可以统一理解为休眠状态,当线程处于这几种状态时,线程是没有cpu的使用权的。
三、java线程之间状态切换是什么样的?
四、创建线程有哪些方式?
- 实现Runnable接口,然后传到Thread作为参数
- 实现Callable接口,然后将Callable接口传入到FutureTask中,再将FutureTask传入到Thread作为参数
Callable实现返回值,futureTask实现异步
- 直接继承Thread,重新run方法
五、interrupt方法
interrupt作为一种线程交互的方式,相比stop温柔多了。对于被interrupt的线程,如果想要接收通知,有以下2种方式:
- 异常
当线程处于 Waiting、Timed_Waiting状态时,如果其他线程调用线程A的interrupt方法,会使线程A返回到Runnable状态,同时线程A的代码会触发InterruptException异常。我们在调用wait、join、sleep方法,都能看的这些方法都会throws interruptException,这个异常的触发条件就是其他线程调用该线程的interrupt方法
当线程A处于Runnable,并且阻塞在java.io.channels.interruptiableChannel上时,如果其他线程调用A的interrupt方法,线程A会触发java.nio.channels.ClosedByinterruptException;而阻塞在java.nio.channels.Selector上时,如果其他线程调用线程A的interrupt方法,线程A会立即返回
- 主动检测
通过主动检测 thread.isInterupted方法,来判断自己是否被中断了