我有一個(gè)抽象類,用于使子類的實(shí)例過期:public abstract class Expirable { private transient Timer timer; protected abstract void onExpire(); protected void setExpire(long delay) { resetExpire(); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { resetExpire(); onExpire(); } }, delay ); } protected void resetExpire() { if (timer != null) { timer.cancel(); timer = null; } }}我擴(kuò)展任何類并覆蓋onExpire,然后我setExpire(delay)從子類(未顯示)調(diào)用:public class MyClass extends Expirable { @Override protected void onExpire() { // expiration code here }}這個(gè)類工作得很好,但timer對象非常昂貴。因?yàn)槲矣袛?shù)萬個(gè)實(shí)例,所以我寫了一個(gè)具有相同功能的廉價(jià)版本,它使用timer一個(gè)固定速率的調(diào)度和一個(gè)queue. 不那么精確,但便宜。public abstract class ExpirableCheap { private static final long COLLECTOR_INTERVAL_MSEC = 1000; private static final int INITIAL_CAPACITY = 128; private static Queue<ExpirableCheap> queue = new PriorityBlockingQueue<>( INITIAL_CAPACITY, Comparator.comparingLong(expirable -> expirable.expiresWhen) );顯然,靜態(tài)代碼塊執(zhí)行一次并定期調(diào)度timer。將timerTask在隊(duì)列和呼叫偷窺onExpire()。怎么了?這運(yùn)行了一段時(shí)間,但突然timerTask不再執(zhí)行。測試時(shí),它工作正常,我無法模擬這種情況,但在生產(chǎn)一段時(shí)間后它失敗了。我不確定會(huì)發(fā)生什么,但我懷疑我在靜態(tài)代碼塊中初始化的靜態(tài)變量在收集子類的最后一個(gè)實(shí)例時(shí)被垃圾收集。然后,當(dāng)類被重用時(shí),靜態(tài)代碼塊不會(huì)再次運(yùn)行。換句話說,它似乎一直有效,直到不再有 which extend ExpirableCheap.奇怪的是queue,為什么我期望在 內(nèi)部發(fā)生異常的原因仍然存在,Runnable我認(rèn)為情況并非如此。如您所見,我嘗試將靜態(tài)代碼塊中的變量timer和timerTask變量移動(dòng)到成員變量中(這沒有幫助)。我也嘗試同步setExpire()and resetExpire(),我相信這也沒有區(qū)別。有人能看到發(fā)生了什么嗎?我是否又犯了另一個(gè)愚蠢的錯(cuò)誤并且我走錯(cuò)了路?有什么建議我可以改變以使其工作嗎?
1 回答

波斯汪
TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超4個(gè)贊
正如@TimBiegeleisen 正確指出的那樣,Java 按預(yù)期工作。當(dāng)收集子類的最后一個(gè)實(shí)例時(shí),抽象超類不會(huì)被垃圾收集。
我的問題是無關(guān)的。
添加回答
舉報(bào)
0/150
提交
取消