После игры с WeakReference и ScheduledExecutorService, я думаю, что теперь я лучше понимаю проблему. Основная проблема в моем коде заключается в следующем методе register (). Он использует анонимный объект Runnable. Проблема с анонимным объектом, подобным этому, заключается в том, что он создает сильную ссылку на родительскую область. Помните, что если вы сделаете поля в родительской области "final", вы можете ссылаться на них из метода run () класса Runnable. Я думал, что я не создаю такой сильный реф, если я не ссылаюсь на что-либо из моего run (). Как показано в этом случае, все, что я делаю в run (), - это вывод некоторой статической строки. Однако, согласно наблюдаемому поведению, такая ссылка, тем не менее, создается.
private void register() {
_scheduler.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
System.out.println("!doing stuff...");
}
}, 1, 1, TimeUnit.SECONDS);
}
Правильный способ выполнения этого вида программирования - создать класс и передать свой объект самостоятельно. Вы также должны держать только слабую ссылку. Код довольно длинный, я просто опубликую реализацию Runnable, которая содержит слабую ссылку на доменный объект Main.
private static class ResourceRefreshRunner implements Runnable
{
WeakReference<Main> _weakRef;
public ResourceRefreshRunner(Main o)
{
_weakRef = new WeakReference<Main>(o);
}
@Override
public void run() {
try {
Main m = _weakRef.get();
if (m != null)
m.shout();
else
System.out.println("object not there, but future is running. ");
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
}
Сейчас в Главном классе у меня есть:
public class Main {
ScheduledExecutorService _poolInstance;
ScheduledFuture<?> _future;
public Main(ScheduledExecutorService p)
{
_poolInstance = p;
_future = _poolInstance.scheduleWithFixedDelay(new ResourceRefreshRunner(this), 1, 1, TimeUnit.SECONDS);
} ...
И финализатор Main:
@Override
protected void finalize() throws Throwable {
try {
System.out.println("bye");
_future.cancel(true);
} finally {
super.finalize();
}
}
С этой настройкой код ведет себя как ожидалось. Например. когда на главный объект больше не ссылаются, включается GC и вызывается финализатор. Еще один эксперимент, который я провел, заключается в том, что без _future.cancel (true); в finalize (), когда объект Main является GC-ed, слабая ссылка в Runnable.run () больше не может разыменовывать объект Main, но поток и задачи все еще работают.