2015-02-09 89 views
21

我維護一個啓動守護程序線程以在後臺執行工作的庫。在常規的Java和Android應用程序中,此線程將啓動一次並在該進程的整個生命週期中運行。它永遠不會退出,沒關係。在應用程序卸載時退出線程

當我的庫包含在支持應用程序卸載的應用程序容器(如Tomcat)中時,應用程序永遠不會卸載。我正在運行的線程擁有對其自己的類的強引用,並阻止整個應用程序被卸載。我的圖書館的用戶無法每次都在不泄漏內存的情況下熱切換他們的應用程序。

當應用程序容器希望卸載我的庫時,獲取信號的最佳方式是什麼?

這是一個不依賴應用程序容器API的小型庫。它不知道它正在運行哪個應用程序容器,而且它不想!

這個庫啓動一個線程的事實是一個實現細節。圖書館的最終用戶不應該知道一個線程正在啓​​動,關閉它並不是他們的責任。

+0

有沒有其他的對象可以檢測垃圾回收? – immibis 2015-02-10 06:26:56

+0

我不確定我是否正確理解您的問題,但可能是這樣的:https://weblogs.java.net/blog/kcpeppe/archive/2011/09/29/mysterious-phantom-reference會有幫助嗎? – 2015-02-10 08:47:05

回答

6

難道你不能確定你的lib是否在過去的x分鐘/秒內被應用程序使用,如果不是,則關閉線程?在下次使用時重新啓動它? java.util.concurrent.ThreadPoolExecutor這樣工作。

+0

這可以工作。這是不幸的,拖延流程驅逐,但不是行不通的。 – 2015-02-09 13:35:06

2

這是一個有趣的問題。你可能想嘗試的一個想法:

讓守護進程線程對你的庫使用弱引用。然後在庫中有一些守護對象,它有finalize()方法取下守護線程。

會這樣的工作?

+0

不幸的是,該庫沒有任何引用返回給應用程序,所以這種方法對我而言不起作用。 – 2015-02-09 05:57:13

+0

傑西 - 啊 - 我想我可能會對使用術語'應用程序'造成一些混淆。我是說你的圖書館。我很確定我所描述的策略會起作用。我會改變我的迴應文本,使其更清楚。 – 2015-02-10 06:00:48

+0

垃圾回收器無法通知應用程序已卸載。值過早收集(卸載前);課程太晚(我的線程退出後)。 – 2015-02-11 13:39:36

7

最好的辦法是提供清理圖書館的方法。最終用戶必須調用它(大概基於處理容器中的應用程序生命週期)。在兼容的servlet容器(例如Tomcat)中使用時,您也可以爲Listener提供Listener,但最終用戶仍需注意並將描述符放入web.xml中。

唯一的另一種選擇是您的最終用戶將不得不創建一個管理線程死的監聽器。我不得不多次做到這一點,並不漂亮。它通常涉及使用反射來獲取線索並殺死它。當然,ThreadDeath異常由一些庫處理,線程拒絕死亡。這就需要更多的反射來清理混亂。

如果你給他們一個簡單的方法來清理圖書館,你的最終用戶會好得多。它認爲他們必須知道你的實現細節,但他們已經這樣做了,因爲你不讓應用程序卸載。

+0

我希望我的圖書館的未來用戶不必發現他們的應用程序不卸載,然後必須搜索修復程序。如果它正常工作,效果會更好! – 2015-02-09 05:59:25

+0

@JesseWilson我完全同意!然而,事實是沒有自動和可靠的方式來檢測您正在運行的Web應用程序,更不用說當應用程序正在卸載時。最好讓用戶容易處理這個問題,而不是讓它變成一個痛苦的問題。 – Rob 2015-02-09 13:34:06

+2

也許你可以提供這個API(供知情消費者立即清理),以及*提供某種基於自動超時的方法,如@Cfx爲(不知情的消費者)提供的建議。 – rewbs 2015-02-10 02:19:25

1

您可以使用ComponentCallbacks2.onTrimMemory()。這是在系統資源不足並且後臺應用程序釋放資源時調用的。

我的經驗是,當onTrimMemory(TRIM_MEMORY_COMPLETE)被調用時,應用程序即將被殺死。

+0

我特別感興趣的是進程繼續運行的情況,但其中的應用程序被卸載。 ComponentCallbacks將無法幫助,因爲Android不會實現卸載類。 – 2015-02-09 13:33:03