取消与关闭(第七章)

取消与关闭

Java中没有提供任何机制来安全得终止线程,但它提供了中断(Interruption),这是一种协作机制,能够使一个线程终止另一个线程当前的工作。
我们很少希望某个任务、线程或服务立即停止,因为这种立即停止会使共享的数据结构处于不一致的状态。相反,在编写任务和服务时可以使用一种协作的方式:当需要停止时,它们首先清楚当前正在执行的工作,然后再结束

1.任务取消

一个可取消的任务必须拥有取消策略(Cancellation Policy),在这个策略中应详细定义取消操作的“How”、“When”以及“What”,即其他代码如何(How)请求取消任务,任务在何时(When)检查是否已经请求了取消,以及在响应取消请求时应执行哪些(What)操作。

取消任务的方式:
1. 设置一个取消标志,任务在每次迭代执行前首先检查此标志以确定任务是否被取消
2. 中断。在任务中如果存在阻塞调用,那么第一种方法将失效,此时,可以通过中断方法取消任务

2.中断

Thread中的中断方法:

public class Thread{
    public void interrupt(){...}
    public boolean isInterrupted(){...}
    /静态的interrupted方法将清除当前线程的中断状态,并返回它之前的值,这也是清除中断状态的唯一方法/
    public static boolean interrupted(){...}
}
    调用interrupt并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。

对中断操作的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己

并非所有阻塞调用都能响应中断操作,wait、sleep、join等将严格处理中断请求,而IO阻塞并不能响应(常规的)中断请求。

3.中断策略

中断策略规定线程如何解释某个中断请求----当发现中断请求时,应该做哪些工作。
最合理的中断策略是某种形式的线程级(Thread Level)取消操作或服务级(Service Level)取消操作:尽快推出,在必要时进行清理,同志某个进程所有者该线程已推出。
大多数可阻塞的库函数都只是抛出InterruptedException作为中断响应:尽快推出执行流程,并把中断消息传递给调用者,从而使调用栈中的上层代码可以采取进一步的操作。
当调用可中断的阻塞方法,例如sleep和wait,有两种策略可以用于处理InterruptedException:
1. 传递异常(可能在执行某个 特定于任务的清理后),从而使你的方法也能成为可中断的阻塞方法
2. 恢复中断状态,从而使调用栈中的上层代码能够对其进行处理

通过Future来实现取消:
ExecutorService.submit将返回一个Future来描述任务。Future拥有一个cancel方法,该方法带有一个boolean类型的参数mayInterruptIfRunning,表示操作能否接受中断,如果为true并且任务正在某个线程中运行,那么这个线程能被中断,如果为false,那么意味着“若任务还没有启动,就不要启动它”。

    当尝试取消某个任务时,不宜直接中断线程池,因为你并不知道当中断请求到达时正在运行什么任务----只能通过任务的Future来实现取消。

4.处理不可中断的阻塞

并非所有的可阻塞方法或阻塞机制都能响应中断,如果一个线程由于执行同步的Socket I/O或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他任何作用。对于那些由于执行不可中断操作而被阻塞的线程,可以使用类似于中断的手段来停止这些线程,但这要求我们必须知道线程阻塞的原因。

5.停止基于线程的服务

应用程序通常会创建拥有多个线程的服务,例如线程池,并且这些服务的生命周期通常比创建它们的方法的生命周期更长。如果应用程序准备退出,那么这些服务所拥有的线程也需要结束。由于无法通过抢占式的方法来停止线程,因此它们需要自行结束。
正确的封装原则是:除非拥有某个线程,否则不能对该线程进行操控,例如:中断线程或者修改线程的优先级等。对于持有线程的服务,只要服务的存在时间大于创建线程的方法的存在时间,那么就应该提供生命周期方法。

线程的所有权是不可传递的:应用程序可以拥有服务,服务也可以拥有工作者线程,但应用程序并不能拥有工作者线程,因此应用程序不能直接停止工作者线程。

6.处理非正常的线程终止

导致线程提前死亡的最主要原因就是RuntimeException,由于这些异常表示出现了某种编程错误或者其他不可修复的错误,因此它们通常不会被捕获,它们不会在调用栈中逐层传递,而是默认地在控制台中输出栈追踪信息,并终止线程。
除了主动捕获异常,在Thread API中提供了UncaughtExceptionHandler,它能检测出某个线程由于未捕获的异常而终结的情况。当一个线程由于未捕获异常而退出时,JVM会把这个事件报告给应用程序提供的UncaughtExceptionHandler,如果没有提供任何异常处理器,那么默认的行为是将栈追踪信息输出到System.err。

public interface UncaughtExceptionHandler {
    void uncaughtException(Thread t, Throwable e);
}
    在运行时间较长的应用程序中,通常会为所有线程的未捕获异常指定同一个异常处理器,并且该处理器至少会将异常信息记录到日志中。

7.JVM关闭

JVM既可以正常关闭,也可以强行关闭。正常关闭的触发方式包括:
1. 当最后一个普通线程结束时(线程分为普通线程和守护线程
2. 调用了System.exit
3. 通过其他特定于平台的方法关闭时(例如发送了SIGINT信号或键入Ctrl-C)

强行关闭JVM的方法:
调用Runtime.halt、在操作系统中kill JVM

1. 关闭钩子

关闭钩子(Shutdown Hook)是指通过Runtime.addShutdownHook注册的但尚未开的线程。
在正常关闭中,JVM首先调用所有已注册的关闭钩子,但JVM并不能保证关闭钩子的调用顺序,在关闭应用程序线程时,如果有线程(包括守护线程)仍然在运行,那么这些线程接下来将与关闭进程并发执行,当所有的关闭钩子都执行结束时,如果runFinalizersOnExit为true,那么JVM将运行终结器,然后再停止。如果关闭钩子或终结器没有执行完成,那么正常关闭进程“挂起”并且JVM必须被强行关闭。当被强行关闭时,只是关闭JVM,而不会运行关闭钩子。
关闭钩子不应该依赖那些可能被应用程序或其他关闭钩子关闭的服务,实现这种功能的一种方式是对所有服务使用同一个关闭钩子而不是每个服务使用一个不同的关闭钩子。
一个关闭钩子的例子:

public void start() {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                LogService.this.stop();
                catch (InterruptedException ignored) {}
            }
        }
    });
}
时间: 2025-01-01 03:30:33

取消与关闭(第七章)的相关文章

Android群英传笔记——第七章:Android动画机制和使用技巧

Android群英传笔记--第七章:Android动画机制和使用技巧 想来,最 近忙的不可开交,都把看书给冷落了,还有好几本没有看完呢,速度得加快了 今天看了第七章,Android动画效果一直是人家中十分重要的一部分,从早期的Android版本中,由于动画机制和绘图机制的不健全,Android的人机交互备受诟病,Android从4.X开始,特别是5.X,动画越来越完善了,Google也开始重视这一方面了,我们本章学习的主要内容有 Android视图动画' Android属性动画 Android动

ArcGIS for Desktop入门教程_第七章_使用ArcGIS进行空间分析 - ArcGIS知乎-新一代ArcGIS问答社区

原文:ArcGIS for Desktop入门教程_第七章_使用ArcGIS进行空间分析 - ArcGIS知乎-新一代ArcGIS问答社区 1 使用ArcGIS进行空间分析1.1 GIS分析基础 GIS的六大功能是数据获取.存储.查询.分析.表达.输出.在前面的内容里已经介绍了使用ArcGIS进行数据获取.存储.查询.表达和输出的过程,本章将介绍如何在ArcGIS中进行地理分析.分析是GIS的核心和灵魂,是GIS区别于一般的信息系统.CAD或者电子地图系统的主要标志之一. GIS分析,就是研究数

Android开发艺术探索——第七章:Android动画深入分析

Android开发艺术探索--第七章:Android动画深入分析 Android的动画可以分成三种,view动画,帧动画,还有属性动画,其实帧动画也是属于view动画的一种,,只不过他和传统的平移之类的动画不太一样的是表现形式上有点不一样,view动画是通过对场景的不断图像交换而产生的动画效果,而帧动画就是播放一大段图片,很显然,图片多了会OOM,属性动画通过动态的改变对象的属性达到动画效果,也是api11的新特性,在低版本无法使用属性动画,但是我们依旧有一些兼容库,OK,我们还是继续来看下详细

struct-C++primer第五版关于第七章类的一个问题

问题描述 C++primer第五版关于第七章类的一个问题 #include #include using namespace std; struct Sales_data{ Sales_data()=default; Sales_data(const string &s):bookNo(s){} Sales_data(const string &s,unsigned n,double p): bookNo(s),units_sold(n),revenue(p*n) {} Sales_dat

> 第七章 异常处理(rainbow 翻译) (来自重粒子空间)

<<展现C#>> 第七章 异常处理(rainbow 翻译) 出处:http://www.informit.com/matter/ser0000002 正文: 第七章   异常处理     通用语言运行时(CLR)具有的一个很大的优势为,异常处理是跨语言被标准化的.一个在C#中所引发的异常可以在Visual Basic客户中得到处理.不再有 HRESULTs  或者 ISupportErrorInfo 接口.    尽管跨语言异常处理的覆盖面很广,但这一章完全集中讨论C#异常处理.你

《.net编程先锋C#》第七章 异常处理(转)

编程|异常处理 第七章 异常处理通用语言运行时(CLR)具有的一个很大的优势为,异常处理是跨语言被标准化的.一个在C#中所引发的异常可以在Visual Basic客户中得到处理.不再有 HRESULTs 或者 ISupportErrorInfo 接口.尽管跨语言异常处理的覆盖面很广,但这一章完全集中讨论C#异常处理.你稍为改变编译器的溢出处理行为,接着有趣的事情就开始了:你处理了该异常.要增加更多的手段,随后引发你所创建的异常. 7.1 校验(checked)和非校验(unchecked)语句当

如何取消电脑关闭IE浏览器时弹出的“是关闭所有选项卡还是当前选项卡”提示

  如何取消电脑关闭IE浏览器时弹出的"是关闭所有选项卡还是当前选项卡"提示         方法一: 在弹出的这个提示窗口中,勾选"总是关闭所有选项卡",然后点击"关闭所有选项卡"按钮,这样下次再关闭IE窗口时,就不会再弹出该提示了. 方法二: 1.打开IE浏览器--"Internet选项"; 2.在"常规"中,点击"选项卡"按钮; 3.取消勾选"关闭多个选项卡时发出警告&q

Knockout应用开发指南 第七章:Mapping插件

原文:Knockout应用开发指南 第七章:Mapping插件 Mapping插件 Knockout设计成允许你使用任何JavaScript对象作为view model.必须view model的一些属性是observable的,你可以使用KO绑定他们到你的UI元素上,当这些observable值改变的时候,这些UI元素就会自动更新. 绝大多数程序都需要从服务器端获取数据,但是由于服务器不知道observable的概念是什么,它只支持简单的JavaScript对象(通常是序列化以后的JSON),

【原创】构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测CLR性能

原文:[原创]构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)-托管资源优化-监测CLR性能 构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)-托管资源优化-监测CLR性能     前言:在上一篇文章中讲述了一些垃圾回收的一些知识,本篇就讲述如何来监测CLR是否导致了一些性能问题.    本篇的议题如下: 内存问题概述(前篇) 托管资源优化(前篇)          对象的生命周期(前篇)          对象的"代"(前篇)          大