关闭

引导使你的应用程序启动并且运行起来,但是迟早你都需要优雅地将它关闭。

当然,你也可以让JVM 在退出时处理好一切,但是这不符合优雅的定义,优雅是指干净地释放资源。

关闭Netty应用程序并没有太多的魔法,但是还是有些事情需要记在心上。

最重要的是,你需要关闭EventLoopGroup,它将处理任何挂起的事件和任务,并且随后释放所有活动的线程。

这就是调用 EventLoopGroup.shutdownGracefully() 方法的作用。

这个方法调用将会返回一个 Future,这个 Future 将在关闭完成时接收到通知。

需要注意的是,shutdownGracefully() 方法也是一个异步的操作,所以你需要阻塞等待直到它完成,或者向所返回的Future 注册一个监听器以在关闭完成时获得通知。

代码

代码清单8-9 符合优雅关闭的定义。

  [java]
1
2
3
4
5
6
7
8
EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class); ... Future<?> future = group.shutdownGracefully(); // block until the group has shutdown future.syncUninterruptibly();

或者,你也可以在调用EventLoopGroup.shutdownGracefully()方法之前,显式地在所有活动的 Channel 上调用 Channel.close() 方法。

但是在任何情况下,都请记得关闭 EventLoopGroup 本身。

源码

  • SingleThreadEventExecutor
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@Override public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) { if (quietPeriod < 0) { throw new IllegalArgumentException("quietPeriod: " + quietPeriod + " (expected >= 0)"); } if (timeout < quietPeriod) { throw new IllegalArgumentException( "timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))"); } if (unit == null) { throw new NullPointerException("unit"); } if (isShuttingDown()) { return terminationFuture(); } boolean inEventLoop = inEventLoop(); boolean wakeup; int oldState; for (;;) { if (isShuttingDown()) { return terminationFuture(); } int newState; wakeup = true; oldState = state; if (inEventLoop) { newState = ST_SHUTTING_DOWN; } else { switch (oldState) { case ST_NOT_STARTED: case ST_STARTED: newState = ST_SHUTTING_DOWN; break; default: newState = oldState; wakeup = false; } } if (STATE_UPDATER.compareAndSet(this, oldState, newState)) { break; } } gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod); gracefulShutdownTimeout = unit.toNanos(timeout); if (oldState == ST_NOT_STARTED) { doStartThread(); } if (wakeup) { wakeup(inEventLoop); } return terminationFuture(); }

个人收获

  1. 原理其实就是线程池的关闭。

  2. 这里应该有好奇心,为什么 shutdown 被废弃了,怎么个优雅法则?

参考资料

《Netty in Action》 P128