Java 中关闭钩子的有用例子?

我试图确保我的 Java 应用程序采取合理的步骤来保持健壮性,其中一部分工作是优雅地关闭。我正在阅读关于 关闭挂钩的文章,实际上我并不知道如何在实践中使用它们。

有实际的例子吗?

假设我有一个非常简单的应用程序,比如下面这个,它将数字写入一个文件,10到一行,每批100个数字,如果程序中断,我希望确保一个给定的批处理完成。我得到了如何注册一个关闭钩,但我不知道如何集成到我的应用程序。有什么建议吗?

package com.example.test.concurrency;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;


public class GracefulShutdownTest1 {
final private int N;
final private File f;
public GracefulShutdownTest1(File f, int N) { this.f=f; this.N = N; }


public void run()
{
PrintWriter pw = null;
try {
FileOutputStream fos = new FileOutputStream(this.f);
pw = new PrintWriter(fos);
for (int i = 0; i < N; ++i)
writeBatch(pw, i);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally
{
pw.close();
}
}


private void writeBatch(PrintWriter pw, int i) {
for (int j = 0; j < 100; ++j)
{
int k = i*100+j;
pw.write(Integer.toString(k));
if ((j+1)%10 == 0)
pw.write('\n');
else
pw.write(' ');
}
}


static public void main(String[] args)
{
if (args.length < 2)
{
System.out.println("args = [file] [N] "
+"where file = output filename, N=batch count");
}
else
{
new GracefulShutdownTest1(
new File(args[0]),
Integer.parseInt(args[1])
).run();
}
}
}
147090 次浏览

你可以这样做:

  • 让关闭钩子将一些 AtomicBoolean (或易失布尔)“ keepRun”设置为 false
  • (可选地,如果工作线程在某些阻塞调用中等待数据,则 .interrupt工作线程)
  • 通过调用工作线程上的 Thread.join()方法,等待工作线程(在您的情况下执行 writeBatch)完成。
  • 终止程序

一些粗略的代码:

  • 加入 static volatile boolean keepRunning = true;
  • Run ()中你变成

    for (int i = 0; i < N && keepRunning; ++i)
    writeBatch(pw, i);
    
  • In main() you add:

    final Thread mainThread = Thread.currentThread();
    Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
    keepRunning = false;
    mainThread.join();
    }
    });
    

That's roughly how I do a graceful "reject all clients upon hitting Control-C" in terminal.


From the docs:

When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt.

That is, a shutdown hook keeps the JVM running until the hook has terminated (returned from the run()-method.