1、优雅的姿态是什么样

当我们触发关闭的操作时,程序接收到关闭进程的指令,程序在关闭之前需要完成以下步骤:

  • 停止接收客户端的连接
  • 执行线程池中未执行完毕的任务
  • 持久化缓存中的数据
  • 清理临时的文件等

这就是我们对于优雅安全的关闭游戏服的目标,按照以上顺序关闭服务器不会造成数据的丢失。

2、如何进行处理

JVM 提供了关闭钩子用来满足以上的需求。关闭钩子实际上是一种 hook 线程,用来监听 JVM 的关闭,当然,该 hook 线程只有在 JVM 正常关闭的情况下才会触发相关操作,强制关闭下无法执行 hook 操作,主要的触发情形有以下几种:

  • 程序正常退出
  • 调用 system.exit() 方法
  • 使用 ctrl+c 命令中断
  • 系统关闭
  • OutOfMemory 引起的程序退出
  • 使用 kill pid 命令中断

注意:kill -9 pid 命令无法触发 shutdown hook 执行,该命令属于强制关闭

3、如何使用钩子

简单使用实例:

public class Test {

	public static void main(String[] args) {

		System.out.println("main exec...");

		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println("监听到JVM关闭操作,执行hook的相关操作...");
			}
		}));

	}
}

对于一个完整的项目来说,关闭时往往需要注册多个关闭钩子进行处理,这些钩子会并发执行操作,JVM 并不能控制其执行的顺序,当钩子执行时 JVM 延迟关闭,所有的钩子操作执行完毕后 JVM 才会退出,所以我们应当尽量减少 hook 操作的时间。另外钩子并发执行的特点,很容易出现死锁和竞态条件等问题,原则上我们应当在一个钩子中执行一系列的相关操作。

以下还有一些需要注意的地方:

  • hook 线程中抛出的异常需要进行处理,否则会中断执行
  • hook 执行逻辑中不能调用 system.exit() 方法,否则会造成死循环
  • system.exit() 方法后注册的钩子无法执行
  • 不能再 hook 中进行 hook 的注册和移除,这会引发非法操作异常
  • 当 JVM 收到 SIGTERM 指令时,hook 操作在一定的时间内没有处理完成,则会被终止
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:PipeSoloSymWide 等,欢迎大家加入,贡献开源。

    2825 引用 • 4212 回帖 • 645 关注
  • 框架
    26 引用 • 217 回帖
感谢    关注    收藏    赞同    反对    举报    分享