2014-11-15 109 views
2

sys.addShutdownHook的scaladoc表示shutdown hooks are NOT guaranteed to be run。现在这是完全合理的,因为如果您将JVM发送到SIGKILL或任何Windows等价物,JVM几乎不能运行关闭挂钩。Scala关机挂钩永不运行?

然而,关机挂钩增加sys.addShutdownHook似乎永远不会运行,虽然那些与Runtime.getRuntime.addShutdownHook运行。

测试 -

scala> val t = new Thread { override def run = println("hi!") } 
t: java.lang.Thread = Thread[Thread-4,5,main] 

scala> Runtime.getRuntime.addShutdownHook(t) 

scala> hi! 
[email protected]:~$ scala 

(跳过启动消息)

scala> val t = new Thread { override def run = println("hi!") } 
t: java.lang.Thread = Thread[Thread-4,5,main] 

scala> sys.addShutdownHook(t.run _) 
res0: scala.sys.ShutdownHookThread = Thread[shutdownHook1,5,main] 

scala> [email protected]:~$ 

文档说“钩子自动注册:返回值可以忽略不计”,所以它不是我们”重新添加由sys.addShutdownHook 返回的线程(并且在任何情况下都会导致“IllegalArgumentException:挂钩先前已注册”)。

此外,调用addShutdownHook返回的线程上运行似乎没有做任何事情,这是可疑的。

回答

10

addShutdownHook类型签名是(source):

def addShutdownHook(body: => Unit): ShutdownHookThread 

因此,这是显而易见的,为什么你的代码不能正常工作。预期的是按名称参数=> Unit,您通过t.run _,返回() => Unit - 这是完全不同的东西。

调用名称参数直到它们被执行时才会运行,将t.run _传递给它意味着函数是在调用名称参数时创建的 - 而不是您自己传递函数的名称参数。

使用

sys.addShutdownHook(t.run) 

代替。或者根本不使用线程,只是传递应该执行的代码:

sys.addShutdownHook(println("hi")) 
+0

有什么区别?如果你编译这个Scala类Foo {def bar(a:=> Unit)=(); def baz(a:()=> Unit)=(); }'两个方法的jvm字节码似乎是相同的,都似乎使用Function0 –

+0

请参阅http://stackoverflow.com/questions/4543228/whats-the-difference-between-and-unit – sschaef

+1

@GeorgeSimms您还可以获得被值丢弃咬伤(见例如http://blog.bruchez.name/2012/10/implicit-conversion-to-unit-type-in​​.html)。正因为如此,你的关机钩实际上是说“创建一个函数't.run _'并把它扔掉”。 –