我的scala程序中有关闭钩子并且在使用ctrl + c退出时工作正常,但是在用户刚退出命令行窗口之后还有一些方法可以执行某些操作,因为不会以这种方式调用shutdown吗?
答案 0 :(得分:1)
我很难想象你能保证资源得到清理,无论如何。您的申请终止的原因有很多:定期终止,例外终止,用户停止流程,机器死亡,......
但是,您可以构建各种安全网:正如您所做的那样,可以定义关闭处理程序,以便在应用程序停止时清理资源。现在,如果你想确保清理一些资源,即使整个过程停止运行,那么你可以创建第二个过程,其唯一目的是检查你的应用程序是否仍然在运行,如果它不是。 t,清理资源。
现在这需要两个进程至少进行通信:一个进程需要知道另一个进程是否仍在运行。
有多种沟通方式。根据您希望设计的复杂程度,有些更适合。我可以想到以下沟通方式:
让一个进程构建您的应用程序。此过程将是另一个的父进程,可以检查另一个进程是否仍在运行
让进程使用远程过程调用(RMI)进行通信。您可以使用方法ping
定义一个返回pong
的接口,允许一个进程检查另一个进程是否仍然存在。
在比RMI更低的级别上使用套接字进行类似的通信。
进程可以通过文件系统进行通信,即一个进程通过写入文件来ping另一个进程,如果另一个进程没有对协议作出反应,则进程清理资源。这可能不如前一种方法可靠,也可能更慢,尽管我没有数据来支持我的直觉。
我不是专家,所以肯定有很多选择。
您可以尝试这样做:
package application
import java.io._
import java.nio.file._
import java.nio.file.attribute.BasicFileAttributes
object Bootstrap {
def main(args: Array[String]): Unit = {
val workingDirectory = Files.createTempDirectory("newTemp")
println("Working Directory: " + workingDirectory)
val processBuilder = new ProcessBuilder("java", "-jar", "/path/to/process.jar", workingDirectory.toAbsolutePath.toString)
processBuilder.directory(workingDirectory.toFile)
val process = processBuilder.start()
new StreamGobbler(process.getErrorStream, "ERROR").start()
new StreamGobbler(process.getInputStream, "OUTPUT").start()
process.waitFor()
println("Process stopped working")
cleanup(workingDirectory)
}
def cleanup(workingDirectory: Path): Unit = {
Files.walkFileTree(workingDirectory, new SimpleFileVisitor[Path]{
override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = {
Files.deleteIfExists(file)
super.visitFile(file, attrs)
}
override def postVisitDirectory(dir: Path, exc: IOException): FileVisitResult = {
Files.deleteIfExists(dir)
super.postVisitDirectory(dir, exc)
}
})
}
}
class StreamGobbler(is: InputStream, `type`: String) extends Thread {
override def run(): Unit = {
val isr = new InputStreamReader(is)
val br = new BufferedReader(isr)
var line = br.readLine()
while (line != null){
System.out.println(`type` + "> " + line)
line = br.readLine()
}
}
}
object Process {
def main(args: Array[String]): Unit = {
val workingDirectory = Paths.get(args(0))
Files.createTempFile(workingDirectory, "Resource", ".txt")
for(i <- 1 to 8) {
println("Process is running")
Thread.sleep(1000)
}
println("Suppose the process got killed here")
}
}
要运行此操作,请创建一个以Process
为入口点的可执行jar,更新"path/to/process.jar"
并运行Bootstrap
。即使您终止调用的子进程,仍应清除资源。
我从ProcessBuilder: Forwarding stdout and stderr of started processes without blocking the main thread获取StreamGobbler
,只将其从Java翻译为Scala。
请注意,如果您的Bootstrap
进程被终止,那么您的资源将无法清理。根据清理工作的重要性,您可以
创建多个独立的清理进程,在没有master的情况下运行(即,让父进程只创建多个清理进程,通信(例如,通过RMI)以独立地协调清除父进程是否仍在运行)
在不同的机器上创建多个独立的清理过程,这些过程通过网络进行通信。即使有当地的电力愤怒,这也可以让你清理。
请注意,为了最大限度地降低应用程序未正确清理的风险,您的清理工作将变得更加复杂。可能还有现有的解决方案(也许应用服务器会为你做这样的事情吗?),但现有的解决方案可能会强制依赖你不需要的东西。