2014-11-15 107 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 _'並把它扔掉」。 –