终结任务(线程)
1.在阻塞时终结
1.1 线程状态
一个线程可以处于以下5种状态之一:
- 新建:已分配必要资源和初始化,有资格获取CPU时间了,之后调度器将把这个线程转变成可运行或则阻塞态
- 就绪:只要调度器把时间片分给线程就可以运行。
- 阻塞:线程可以运行,但有某个条件组织它运行(比如IO阻塞)。该状态下调度器将忽略该线程,直到重新进入就绪态(比如IO结束了就会重新进入就绪态)。
- 运行状态: 线程正在占用CPU运行
- 死亡:死亡或则终止态的线程将是不可再调度的,也不会再得到CPU时间,任务已结束不可再运行。死亡方式是:一般是run()函数返回,但是任务的线程还可以被中断。
1.2 进入阻塞态方法:
- 调用sleep(millisecond)方法使任务进入休眠状态。
- 调用wait()使线程挂起,直到线程得到了notify()或则notifyAll()的消息。才会再进入就绪状态。
- 任务在等到某个IO完成
- 任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为其余的方法已经获取了这个锁。
1.3 中断线程
我们在run()方法的中间打断这个线程的运行,一个最重要的是:当我们打断被阻塞的任务时,可能需要清理资源。所以在java中这种异常中断用到了异常。
Thread类的对象可以调用interrupt()方法来终止被阻塞的线程(比如正在调用sleep等方法),并抛出InterruptedException。当抛出异常或则该任务调用Thread.interrupted()方法的时候,中断状态将被复位(默认false)。Thread.interrupted()方法(这里是线程实例对象的方法)提供了离开run()循环而不抛出异常的第二种方式。
但是通过Executor来管理我们的线程的时候,我们并不能获取到线程对象,也就不能通过线程对象来调用interrupt()方法。这时可以通过在Executor上调用shutdownNow(),这时Executor将发送interrupt()给所有Executor启动的线程。如果我们想终止Executor中的某一个线程,那么执行这个这个线程时就通过submit()方法而不是execute()方法,通过submit()的返回类型来终止该线程。