取消与关闭
7 取消与关闭
7.1.5通过Future来实现取消
Future.get抛出异常,当你知道不在需要这个结果,可以调用Future.caneel来取消任务。
7.1.6 处理不可中断的阻塞(非标准的取消)
在Java库中,许多可阻塞的方法都是通过提前返回或者抛出InterruptedException来响应中断请求的,然而,并非所有的可阻塞方法或者阻塞机制都能响应中断;如果一个线程由于执行同步的Socket I/O或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他任何作用。
对于那些由于执行不可中断操作而被阻塞的线程,可以使用类似于中断的手段来停止这些线程,但这要求我们必须知道线程阻塞的原因。
Java.io包中的同步Socket I/O。在服务器应用程序中,最常见的阻塞I/O形式就是对套接字进行读取和写人。虽然InputStream和OutputStream中的read和write等方法都不会响应中断,但通过关闭底层的套接字,可以使得由于执行read或write等方法而被阻塞的线程抛出一个SocketException。
Java.lo包中的同步I/O。当中断一个正在InterruptibleChannel上等待的线程时,将抛出ClosedByInterruptException并关闭链路(这还会使得其他在这条链路上阻塞的线程同样抛出ClosedByInterruptException )。当关闭一个InterruptibleChannel时,将导致所有在链路操作上阻塞的线程都抛出AsynchronousCloseException。大多数标准的Channel都实现了IntemtptibleChannel。
Selector的异步I/O。如果一个线程在调用Selector.select方法(在java.nio.channels中)
时阻塞了,那么调用close或wakeup方法会使线程抛出ClosedSelectorException并提前返回。
获取某个锁。如果一个线程由于等待某个内置锁而阻塞,那么将无法响应中断,因为线程认为它肯定会获得锁,所以将不会理会中断请求。但是,在Lock类中提供了lockInterruptibly方法,该方法允许在等待一个锁的同时仍能响应中断。
7.1.7 采用newTaskFor来封装非标准的取消
这是Java 6在ThreadPoolExecutor中的新增功能。当把一个Callable提交给ExecutorService时submit方法会返回一个Future, 我们可以通过这个Future来取消任务。newTaskFor是一个工厂方法,_它将创建Future来代表任务。newTaskFor还能返回一个RunnableFuture接口,该接口扩展了Future和Runnable(并由FutureTask实现)。
通过改写interrupt方法,ReaderThread可以取消基于套接字的线程。同样,通过改写任务的Future.cancel方法也可以实现类似的功能。
SocketUsingTask实现了CancellableTask,并定义了Future.cancel来关闭套接字和调用super.cancel。如果SocketUsingTask通过其自己的Future来取消,那么底层的套接字将被关闭并且线程将被中断。因此它提高了任务对取消操作的响应性:不仅能够在调用可中断方法的同时确保响应取消操作,而且还能调用可阻调的套接字I/O方法。
7.2停止基于线程的服务
应用程序通常会创建拥有多个线程的服务,例如线程池,并且这些服务的生命周期通常比创建它们的方法的生命周期更长。如果应用程序淮备退出,那么这些服务所拥有的线程也需要结束。由于无法通过抢占式的方法来停止线程,因此它们需要自行结束。
封装原则: 除非拥有某个线程,否则不能对该线程进行操控。线程池是其工作者线程的所有者。如果要中断这些线程,那么应该使用线程池。
线程的所有权是不可传递的。应用程序可以拥有服务,服务可以拥有工作者线程。但应用程序并不能拥有工作者线程,因此应用程序不能直接停止工作者线程。