Сообщение имеет список подписчиков.
Каждый раз, когда подписчик открывает сообщение, количество подписчиков уменьшается на единицу. Итак, у вас есть поток, ищущий сообщения с числом подписчиков = 0.
Это плохая идея.
Вы должны создать очередь удаления объектов. Каждый раз, когда подписчик открывает сообщение, он проверяет количество подписчиков. Если ноль, подписчик сообщения сам отправляет сообщение в очередь удаления. Теперь потоку GC необходимо отслеживать только очередь удаления.
Зачем вообще иметь счетчик? Список подписчиков сообщений - это связанный список токенов. Каждый подписчик связан с одним токеном в списке. Токен сообщает подписчику, что есть сообщение.
Если очередь сообщений функционирует в сети, для каждого подписчика создается токен, и токен связывается в циклический список. Для каждого токена в списке генерируется соответствующий токен для отправки абоненту. Когда абонент запрашивает получение сообщения, он отправляет свой токен аутентификации администратору очередей сообщений. Управление очередью сообщений выполняет авторизацию токена и позволяет подписчику получить доступ к сообщению, а затем отсоединяет токен от списка.
Независимо от того, является ли это сетевая очередь сообщений или локальная системная очередь, когда последний токен не связан (это круговой список - вы бы знали, что это последний токен), сообщение отправляется в очередь удаления.