25 关于 Signal Dispatcher

Posted 蓝风9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了25 关于 Signal Dispatcher相关的知识,希望对你有一定的参考价值。

前言

呵呵 最近看到一篇文章, [讨论] 通过kill -3 pid 来输出Thread Dump日志信息的时效性 

呵呵 关于常见的几个线程 AttchListener, Signal Dispatcher, Reference Handler, Finalizer, 虽然 平时使用的不是很多吧, 但是 还是可以了解一下的 

这里 我们便来看一下 Signal Dispatcher 这个线程吧 

一下的相关代码, 截图如果没有特殊说明 基于 jdk9 

测试用例

package com.hx.test05;

import sun.misc.Signal;
import sun.misc.SignalHandler;

/**
 * SignalHandler
 *
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2020-05-05 10:53
 */
public class Test24SignalHandler 

  // Test24SignalHandler
  public static void main(String[] args) throws Exception 

    Signal.handle(new Signal("ALRM"), new SignalHandler() 
      @Override
      public void handle(Signal signal) 
        System.out.println(signal);
      
    );

    // 发送信号
//    Signal.raise(new Signal("ALRM"));
    System.in.read();

  


测试代码里面 给 ALRM 这个信号, 注册了一个 signalHandler 

那么 怎么给 vm 发送信号呢?, 通过 kill 命令, kill -14 $pid, 14 号信号, 就是这里的 ALRM 

然后 可以看到 经过 signalHandler 的业务处理, 控制台 输出了 这个信号的相关信息 

Signal Dispatcher

我们来看一下 Signal Dispatcher 的初始化, 以及它 主要做的事情  

这里创建了 java.lang.Thread 对象, 并添加到了 系统线程组 里面, 然后下面 还设置了 本地线程, 优先级, 守护线程 的相关配置 

创建了一个 本地线程(C层面), 并将它们互相建立关系, 并启动线程 

Signal Dispatcher 做的事情 

可以看到 就是不断等待 信号过来, 然后进行处理 

对于 SIGBREAK/SIGQUIT 信号, 特殊处理, 输出 堆栈信息, JNI信息, 死锁, 堆的信息 等等 

对于 其他的 信号 将业务委托给 sun.misc.Signal 

sun.misc.Signal 

java 层面的这个 Signal 主要是维护了 Signal 和 java层面的 Signal.Handler 之间的关系, 另外的这个 signals 是辅助使用存放了 Signal 的 number 到 Signal 的映射 

构造方法, 根据 Signal 的名字, 来查询对应的 Signal, 如果是 未注册的 Signal 抛出异常 

注册 Signal 和 SignalHandler 的映射, 只保留 java 层面的 handler 

发送一个信号, 更下面是直接 不同的平台 委托相关的函数发送信号 

信号的处理, 根据 Signal 的 number 查询 Signal, 然后查询其 注册的 handler, 如果有 启动一个线程 来处理 handler 的业务 

整理一下流程

1. 程序中注册了 SIGALRM -> alrmSignalHandler 的映射关系 

2. 通过终端 kill 命令 或者 程序中 raise 发送信号 

3. vm 里面 Signal Dispatcher 线程检测到这个信号, 因为不是 SIGBREAK/SIGQUIT, 所以 将信号委托给了 sum.misc.Signal 来处理 

4. sum.misc.Signal 里面查询 SIGALRM 对应的  handler, handler 存在, 接下来新起一个 线程来处理 handler 的业务 

以下运行时截图来自于 jdk8 

Signal.name 

呵呵 之前将 ALRM 传递为 SIGALRM, 结果在 jdk8 和 jdk9 里面都报错了 

相信通过上面的 jdk9 的 Signal 的构造方法 你很清楚报错的原因是什么, 那么 jdk8 报错的原因呢? 

做映射的 信号量名称 本身就没有 SIG 前缀 

jdk9 的实现是这样子的, 构造方法中限定不能以 SIG 开头, vm 这一层 如果不以 SIG 开头, 添加上 SIG 前缀 

HUB, INT, TERM 信号

在 System.initializeSystemClass 的时候 调用了 Terminator.setup 

unix, 类unix 操作系统上面是这样  

windows 操作系统上面是这样

注册了这几个信号的 signalHandler, 使用 Shutdown.exit 来关闭系统

Signal already used by VM or OS

mac, unix, 类unix 相关操作系统 上面是这样, 只是可能各个 平台 注册的忽略的信号量不一样 

windows 上面是这样 

返回 -1 的情况就回 抛出该异常 

jdk9 上面 name 以 SIG 开头也会抛出该异常 

完 

参考

[讨论] 通过kill -3 pid 来输出Thread Dump日志信息的时效性 

以上是关于25 关于 Signal Dispatcher的主要内容,如果未能解决你的问题,请参考以下文章

默认线程,如 DestroyJavaVM、Reference Handler、Signal Dispatcher

关于Filter配置中dispatcher的使用

关于避免模糊查询索引时效问题

关于WARN Dispatcher:68 - Could not find action or result报错

Struts2 源码分析——调结者(Dispatcher)之action请求

Struts2 源码分析——调结者(Dispatcher)之action请求