Java тестирование: как запустить пользовательский код, когда экземпляры получают право на G C? - PullRequest
0 голосов
/ 12 января 2020

Я хочу знать, есть ли способ определить, когда экземпляр CompletableFuture получает право на сборку мусора до того, как кто-либо вызвал .get() на нем. Я хочу сделать это обнаружение во время Java тестирования, где я могу использовать любые инструменты из PowerMockito.


Длинное объяснение:

Мы реализуем асинхронные операции, используя методы, которые возвращают CompletableFuture s, и эти фьючерсы завершаются после завершения операции. Зачастую асинхронная операция включает в себя вызов другой асинхронной операции как часть ее задачи, а затем мы используем .thenCompose() для будущего этой подзадачи и возвращаем результат, чтобы взять результат подзадачи и потенциально выполнить некоторую дополнительную обработку, и затем завершите будущее нашей основной задачи.

Иногда, когда результат подзадачи не используется, люди забывают вызвать .thenCompose() или любые другие похожие методы на будущее, возвращаемые подзадачей; вместо этого они просто отбрасывают будущее, которое возвращается, как если бы это был синхронный вызов. Это может заставить нас завершить будущее основной задачи до выполнения подзадачи, что может вызвать тонкие условия гонки в нашем коде.

Теперь я знаю, что выбрасываемое будущее не всегда неверно; возможно, вы хотите завершить sh свою основную задачу, не дожидаясь, пока подзадача завершится sh. Давайте предположим, ради этого вопроса, что в случаях использования в нашем коде мы всегда будем ждать окончания подзадачи до sh перед завершением основной задачи. Я знаю, что также возможно использовать что-то вроде .applyToEither(), чтобы завершить будущее, когда завершится одно из двух будущих событий, а другое будущее отброшено; давайте предположим, ради этого вопроса, что мы никогда не используем это в нашем коде.

Я подумал, что один из способов определить, когда будущее отбрасывается без использования, - это определить, когда оно становится пригодным для сбора мусора (т.е. в программе больше нет активных ссылок на нее), без вызова .get() (поскольку все методы, использующие результат будущего вызова .get() для него).

I хотя единственный способ сделать это может заключаться в том, чтобы обернуть метод .get(), чтобы записать, что использовалось будущее, и обернуть метод .finalize(), чтобы проверить, было ли использовано будущее. Тем не менее, я не думаю, что CompletableFuture переопределяет finalize(), и я не уверен, смогу ли я обернуть его в любом случае. И даже если бы я мог обернуть .finalize(), многие места говорят, что не следует полагаться на .finalize(), потому что он вызывается не сразу, когда объект подходит для сбора мусора, а когда сборщик мусора определяет, что объект имеет право, что может быть неопределенное количество времени позже. Поэтому мне нужно как-то принудительно запустить сборщик мусора и вызвать .finalize() для всех подходящих объектов в конце каждого теста, чтобы это работало. Возможно ли это?

Альтернативно, есть ли у вас какие-либо другие предложения относительно того, как обнаружить, что CompletableFuture не использовался (т. Е. .get() никогда не вызывался до его уничтожения).

...