Как обеспечить сборку мусора FutureTask, который передается в ThreadPoolExecutor, а затем отменяется? - PullRequest
9 голосов
/ 07 февраля 2011

Я отправляю Callable объекты на ThreadPoolExecutor, и они, похоже, торчат в памяти.

Глядя на дамп кучи с помощью инструмента MAT для Eclipse, можно увидеть, что Callable объектына него ссылается переменная FutureTask$Sync s callable .На FutureTask$Sync ссылается переменная FutureTask sync .На FutureTask ссылается FutureTask$Sync эта переменная $ 0 .

Я читал об этом ( здесь , здесь и на SO) и FutureTask кажется, что вызываемый объект включен в ThreadPoolExecutor submit () содержит ссылку на вызываемый объект навсегда.

Что меня смущает, так этокак гарантировать, что FutureTask будет собирать мусор, чтобы он не продолжал удерживать вызываемое в памяти и хранить что-либо, что вызываемое может быть в памяти?

Просто чтобы подробнее рассказать о моей конкретной ситуацииЯ пытаюсь реализовать ThreadPoolExecutor таким образом, чтобы при необходимости можно было отменить все представленные задачи.Я пробовал несколько различных методов, которые я нашел в SO и других местах, таких как полное выключение исполнителя (с помощью shutdown(), shutdownNow() и т. Д.), А также сохранение списка фьючерсов, возвращаемых на submit() и вызов отмены для всех них.а затем очистить список фьючерсов.В идеале я хотел бы не выключать его, а просто cancel() и очищать при необходимости.

Кажется, что все эти методы не имеют значения.Если я отправлю вызов в пул, есть большая вероятность, что он останется без дела.

Что я делаю не так?

Спасибо.

Редактировать:

По запросу, вот конструктор для ThreadPoolExecutor.

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}

После дальнейшего тестирования я могу видеть, что если я позволю задачам, которые были переданы в ThreadPoolExecutorзакончить, то нет утечки.Если я попытаюсь отменить их в любом случае, например:

shutdownNow()

Или сохранить ссылку на будущее и вызвать отмену позже:

Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);

Или, удалив их из очередис такими методами, как:

getQueue.drainTo(someList)

или

getQueue.clear()

или с циклическим просмотром сохраненных ссылок на фьючерсы и вызовом:

getQueue.remove(task)

Любой из этих случаев вызывает FutureTaskпридерживаться, как описано выше.

Итак, реальный вопрос во всем этом заключается в том, как правильно отменить или удалить элементы из ThreadPoolExecutor, чтобы FutureTask собирал мусор и не просачивался вечно?

Ответы [ 4 ]

4 голосов
/ 16 декабря 2012

Согласно этой записи , вы можете позвонить purge на исполнителя.

1 голос
/ 08 марта 2011

Я не мог заставить что-либо работать, поэтому я нашел следующее решение.Вот приблизительный обзор: я создал массив в ThreadPoolExecutor, который отслеживал runnables, которые были в очереди.Затем, когда мне нужно было отменить очередь, я перебрал и вызвал метод отмены для каждого из исполняемых файлов.В моем случае все эти runnables были пользовательским классом, который я создал, и их метод cancel просто устанавливал флаг отмены.Когда очередь запускает следующую для обработки, при запуске запускаемого объекта она увидит, что она отменена, и пропустит фактическую работу.

Таким образом, все выполняемые элементы затем просто быстро вымываются один за другим,он видит, что он был отменен.

Возможно, это не лучшее решение, но оно работает для меня и не приводит к утечке памяти.

1 голос
/ 07 февраля 2011

В качестве обходного пути вы могли бы сделать что-то вроде:

class ClearingCallable<T> implements Callable<T> {
    Callable<T> delegate;
    ClearingCallable(Callable<T> delegate) {
        this.delegate = delegate;
    }

    T call() {
        try {
            return delegate.call();
        } finally {
            delegate = null;
        }
    }
}
0 голосов
/ 05 июля 2016

См .: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html

Будущее представляет собой результат асинхронных вычислений. Если результат не может быть получен с использованием метода get, тогда произойдет утечка памяти!

Если вы не хотите использовать асинхронный результат, используйте Runnable install Callable.

...