java 钩子线程_java-钩子线程

在线上Java程序中经常遇到进程程挂掉,一些状态没有正确的保存下来,这时候就需要在JVM关掉的时候执行一些清理现场的代码。Java中得ShutdownHook提供了比较好的方案。

JDK在1.3之后提供了Java Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在以下几种场景被调用:

1)程序正常退出

2)使用System.exit()

3)终端使用Ctrl+C触发的中断

4)系统关闭

5)使用Kill pid命令干掉进程

注:在使用kill -9 pid是不会JVM注册的钩子不会被调用。

在JDK中方法的声明:

public void addShutdownHook(Thread hook)

参数

hook – 一个初始化但尚未启动的线程对象,注册到JVM钩子的运行代码。

异常

IllegalArgumentException – 如果指定的钩已被注册,或如果它可以判定钩已经运行或已被运行

IllegalStateException – 如果虚拟机已经是在关闭的过程中

SecurityException – 如果存在安全管理器并且它拒绝的RuntimePermission(“shutdownHooks”)

代码示例:

使用Timer模拟一个工作线程,该线程重复工作十次,使用System.exit()退出,在清理现场代码CleanWorkThread 中,取消timer运行,并输出必要的日志信息。

package com.netease.test.java.lang;

import java.util.Timer;

import java.util.TimerTask;

import java.util.concurrent.atomic.AtomicInteger;

/** * Date: 14-6-18 * Time: 11:01 * 测试ShutdownHook */

public class TestShutdownHook {

//简单模拟干活的

static Timer timer = new Timer("job-timer");

//计数干活次数

static AtomicInteger count = new AtomicInteger(0);

/** * hook线程 */

static class CleanWorkThread extends Thread{

@Override

public void run() {

System.out.println("clean some work.");

timer.cancel();

try {

Thread.sleep(2 * 1000);//sleep 2s

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public static void main(String[] args) throws InterruptedException {

//将hook线程添加到运行时环境中去

Runtime.getRuntime().addShutdownHook(new CleanWorkThread());

System.out.println("main class start ..... ");

//简单模拟

timer.schedule(new TimerTask() {

@Override

public void run() {

count.getAndIncrement();

System.out.println("doing job " + count);

if (count.get() == 10) { //干了10次退出

System.exit(0);

}

}

}, 0, 2 * 1000);

}

}

当发生了System.exit(int)时,希望在系统退出前,执行一点任务来做一些资源方面的回收操作,ShutdownHook可以达到这个目的,它利用hook思路来实现,有些时候也把它叫作“钩子“。

假如在系统中通过Runtime.getRuntime().exec()或new ProcessBuilde()启动了子进程(Process),这个子进程一直在运行中,在当前进程退出时,子进程未必会退出,但此时业务上希望将它退出,就可以利用这一点。例如可以这样写:

Runtime.getRuntime().addShutdownHook()

{

new Thread()

{

public void run()

{

processer.destroy();

}

}

}

这里需要注意的是,传入参数是通过new Thread()创建的线程对象,在Java进程调用exit()时,会调用该线程对象的start()方法将其运行起来,所以不要手工先启动了。另外,这种回调线程就不要设定为死循环程序,否则就无法退出了。

再简单阐述下原理,大家也可以自行分析源码得到答案。

java.lang包下有一个Shutdown类,提供了一个Runnable []hooks数组,数组的长度为10,也就是最多定义10个hook(这与程序写入多少个线程回调没有关系,下面会介绍,提供add()方法来注册新的hook对象)

在java.lang.ApplicationShutdownHooks的static匿名块中,通过add()方法注册了一个hook,在run()方法内部的静态方法runHooks(),它内部用一个IdentityHashMap来存放hook信息,可以通过add()方法来添加,而程序中定义的回调线程都放在了这里,它自身用hook的形式存放在于hooks列表中,如下所示:

class ApplicationShutdownHooks

{

static

{

Shutdown.add(1 /* shutdown hook invocation order*/,

new Runnable()

{

public void run()

{

runHooks();

}

}

);

}

}

当调用Runnable.getRunnable().addShutdownHook(Thread)方法时,会间接调用ApplicationShutdownHooks.add(Thread)将线程放到IdentityHashMap中。

当调用System.exit(int)方法时,会间接调用Shutdown.exit(int)方法,再调用sequence()->runHooks()方法,调用如下所示:

/* Run all registered shutdown hooks */

private static void runHooks() {

for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {

try {

Runnable hook;

synchronized (lock) {

// acquire the lock to make sure the hook registered during

// shutdown is visible here.

currentRunningHook = i;

hook = hooks[i];

}

if (hook != null) hook.run();

} catch(Throwable t) {

if (t instanceof ThreadDeath) {

ThreadDeath td = (ThreadDeath)t;

throw td;

}

}

}

}

循环中的一个hook对象就是由ApplicationShutdownHooks的匿名块定义的,因此会调用ApplicationShutdownHooks类的run()方法,再调用它的runHooks()方法,这个runHooks()方法如下所示:

/* Iterates over all application hooks creating a new thread for each

* to run in. Hooks are run concurrently and this method waits for

* them to finish.

*/

static void runHooks() {

Collection threads;

synchronized(ApplicationShutdownHooks.class) {

threads = hooks.keySet();

hooks = null;

}

for (Thread hook : threads) {

hook.start();

}

for (Thread hook : threads) {

try {

hook.join();

} catch (InterruptedException x) { }

}

}

从这个方法中取出所有的Thread,然后将线程启动起来,最后通过join()方法等待各个线程结束动作。换句话说,在线程关闭前,对多个回调任务的处理方式是每个任务单独有一个线程处理,而不是所有的任务在一个线程中串行处理。

Runtime.getRuntime().removeShutdownHook用于删除一个钩子线程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/475243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 604. 迭代压缩字符串

文章目录1. 题目2. 解题1. 题目 对于一个压缩字符串&#xff0c;设计一个数据结构&#xff0c;它支持如下两种操作&#xff1a; next 和 hasNext。 给定的压缩字符串格式为&#xff1a;每个字母后面紧跟一个正整数&#xff0c;这个整数表示该字母在解压后的字符串里连续出现的…

java郝斌_郝斌Java自学教程全集打包

课程介绍&#xff1a;1_Java概述_12_Java概述_23_Java概述_34_Java的卸载5_Java的安装6_环境变量的设置7_常见dos命令 文件名和类名不同时编译运行的问题8_变量命名规则 数据类型 运算符 格式化输出 流程控制9_复习上节课10_类和对象11_内存分配12_访问控制符_113_访问控制符_2…

LeetCode 1056. 易混淆数(哈希)

文章目录1. 题目2. 解题1. 题目 给定一个数字 N&#xff0c;当它满足以下条件的时候返回 true&#xff1a; 原数字旋转 180 以后可以得到新的数字。 如 0, 1, 6, 8, 9 旋转 180 以后&#xff0c;得到了新的数字 0, 1, 9, 8, 6 。 2, 3, 4, 5, 7 旋转 180 后&#xff0c;得到…

hoj2677 Instruction Set // poj3253Fence Repair 哈夫曼树

/* 哈弗曼编码&#xff0c;比如权值为 a:1 b:1 c:2 d:3 e:5 f:6 的树 1.开始时由最小的两个数 a:1 b:1组成一棵树 2.接着由新的最小的两个数 2 c:2 d:3 e:5 f:6 中的 2 c:2组成新的树 3.接着由最小的两个数 4 d:3 组成新的树 4.接着由最小的两个数 e:5 f:6 组成一棵树 5.接着由…

java数组的实现_Java数组HashCode实现

这很奇怪。一位同事询问了java中myArray.hashCode()的实现。我以为我知道&#xff0c;但是后来我进行了一些测试。检查下面的代码。我注意到的奇怪想法是&#xff0c;当我编写第一个系统时&#xff0c;结果是不同的。请注意&#xff0c;这几乎就像报告内存地址并修改类一样&…

LeetCode 624. 数组列表中的最大距离

文章目录1. 题目2. 解题2.1 暴力超时2.2 优化1. 题目 给定 m 个数组&#xff0c;每个数组都已经按照升序排好序了。 现在你需要从两个不同的数组中选择两个整数&#xff08;每个数组选一个&#xff09;并且计算它们的距离。 两个整数 a 和 b 之间的距离定义为它们差的绝对值 |…

strcpy()函数一个简单那程序来了解一下它。。

View Code #include <stdio.h>#include <string.h>int main() { char a[5] "ABCD"; char b[8] "abcdefg"; char c[8] "abcdefg"; char d[5] "ABCD";strcpy(a,b); //长的复制给短的strcpy(c,d);//短的复制给长的print…

java怎么调用7zip进行压缩_JAVA使用7-zip解压缩带密码的Zip文件(非Proccess方法)...

首先到sourceforge网站下载sevenzipjbinding压缩包我下载的版本是sevenzipjbinding-4.65-1.04-rc-extr-only-AllWindows.zippublicvoidunzipDirWithPassword( final String sourceZipFile ,final String destinationDir , final String password ){RandomAccessFile randomAcce…

LeetCode 156. 上下翻转二叉树(DFS)*

文章目录1. 题目2. 解题1. 题目 给定一个二叉树&#xff0c;其中所有的右节点要么是具有兄弟节点&#xff08;拥有相同父节点的左节点&#xff09;的叶节点&#xff0c;要么为空 将此二叉树上下翻转并将它变成一棵树&#xff0c; 原来的右节点将转换成左叶节点。返回新的根。 …

httpd 分页_更改 Apache httpd.conf 配置文件

提示&#xff1a;如果在虚拟主机商配置&#xff0c;请直接配置第三、四步&#xff0c;因为支持 .htaccess 的空间已经配置好了前面两步。用编辑器打开 Apache 配置文件 httpd.conf(该文件位于 Apache 安装目录Apache2conf)&#xff0c;并按如下步骤修改&#xff0c;。一、加载了…

C#23种设计模式WebCast讲解笔记大全(25讲)

C#面向对象设计模式第一讲&#xff1a;面向对象设计模式与原则 C#面向对象设计模式第二讲&#xff1a;Singleton Pattern单件模式&#xff08;创建型模式&#xff09; C#面向对象设计模式第三讲&#xff1a;Abstract Factory Pattern 抽象工厂模式&#xff08;创建型模式&#…

textlayout Java_Java TextLayout.getBounds方法代码示例

import java.awt.font.TextLayout; //导入方法依赖的package包/类/*** {inheritDoc}*/Overridepublic void paintComponent(Graphics g) {updateSizes();Graphics2D g2d (Graphics2D) g;chatDisplay.removeOldMessages();Dimension size getSize();if (freeColClient.isMapEd…

LeetCode 311. 稀疏矩阵的乘法

文章目录1. 题目2. 解题2.1 暴力求解2.2 选取都不为0的行和列相乘1. 题目 给你两个 稀疏矩阵 A 和 B&#xff0c;请你返回 AB 的结果。 你可以默认 A 的列数等于 B 的行数。 请仔细阅读下面的示例。 示例&#xff1a; 输入&#xff1a; A [[ 1, 0, 0],[-1, 0, 3] ] B [[ 7…

jQuery UI应用--滑块Slider

1、 Animate&#xff1a; 类型Boolean 默认值false a) 用处&#xff1a;单击滑动区域时&#xff0c;滑块是否使用动画效果平滑移动到单击位置。 b) 代码示例&#xff1a; 创建实例时设置属性值 $(".class").slider({animate:true}); 实例化后得到…

java部署jar还是war优劣_详解Spring Boot 部署jar和war的区别

本文介绍了Spring Boot 部署jar和war两种方式的区别,分享给大家,具体如下: 1、 packaging的方式不同,一种设置成jar一种是war xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 cn.vcyber.www vcybe…

创业产品经理需要懂技术吗?

作为一位工程师&#xff0c;和一位在不断追求更好产品的设计人员。个人认为&#xff0c;产品经理最好是这样的&#xff1a;一、 精通技术。技术很容易框住人的思想&#xff0c;要不特别精通&#xff0c;能随时跳出技术的束缚&#xff0c;带给产品真正的提升。一般这种产品经理会…

LeetCode 281. 锯齿迭代器(map+vector)

文章目录1. 题目2. 解题1. 题目 给出两个一维的向量&#xff0c;请你实现一个迭代器&#xff0c;交替返回它们中间的元素。 示例: 输入: v1 [1,2] v2 [3,4,5,6] 输出: [1,3,2,4,5,6]解析: 通过连续调用 next 函数直到 hasNext 函数返回 false&#xff0c;next 函数返回值的…

[转载] 杜拉拉升职记——39 充满变数的时期

来源&#xff1a;李可. 杜拉拉升职记(第三版). 西安: 陕西师范大学出版社, 2010, 5. 39 充满变数的时期 何好德和几个销售总监分别谈了话。Tony林事先自然也多少听到些风声&#xff0c;等正式证实了&#xff0c;还是感觉郁闷极了&#xff0c;表面还得装没事人一样&#xff0c;知…

LeetCode 186. 翻转字符串里的单词 II

文章目录1. 题目2. 解题1. 题目 给定一个字符串&#xff0c;逐个翻转字符串中的每个单词。 示例&#xff1a; 输入: ["t","h","e"," ","s","k","y"," ","i","s","…

java自动的废料收集_Java 垃圾收集机制

对象引用Java 中的垃圾回收一般是在 Java 堆中进行&#xff0c;因为堆中几乎存放了 Java 中所有的对象实例。谈到 Java 堆中的垃圾回收&#xff0c;自然要谈到引用。在 JDK1.2 之前&#xff0c;Java 中的引用定义很很纯粹&#xff1a;如果 reference 类型的数据中存储的数值代表…