ConcurrentLinkedQueue$Node остается в "куче" после того, как удалят ()

У меня есть многопоточная запись приложения и чтение ConcurrentLinkedQueue, который концептуально привык к задним записям в списке/таблице. Я первоначально использовал ConcurrentHashMap для этого, которое работало хорошо. Новое требование потребовало, чтобы отслеживание записей порядка вошло, таким образом, они могли быть удалены в самом старом первом порядке, в зависимости от некоторых условий. ConcurrentLinkedQueue, казалось, был хорошим выбором, и функционально он работает хорошо.

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

То, что, кажется, происходит, у меня есть запись впереди очереди, которая произошла, скажите несколько 100K записи назад. У очереди, кажется, есть ограниченное количество настроенных записей (размер () == 100), но при профилировании, я нашел, что были ~100K объекты ConcurrentLinkedQueue$Node в памяти. Это, кажется, дизайном, просто глядящим на источник для ConcurrentLinkedQueue, удаление просто удаляет ссылку на хранивший объект, но оставляет связанный список на месте для повторения.

Наконец мой вопрос: существует ли "лучший" ленивый способ обработать набор этой природы? Я люблю скорость ConcurrentLinkedQueue, я просто, наклон предоставляет неограниченную утечку, которая, кажется, возможна в этом случае. В противном случае кажется, что я должен был бы создать вторую структуру к порядку треков и могу иметь те же проблемы плюс беспокойство синхронизации.

9
задан Steve Jackson 30 March 2010 в 17:17
поделиться

2 ответа

На самом деле здесь происходит то, что метод remove подготавливает поток опроса для обнуления связанной ссылки.

ConcurrentLinkedQueue - это неблокирующая потокобезопасная реализация очереди. Однако когда вы пытаетесь опросить узел из очереди, это двухфункциональный процесс. Сначала вы обнуляете значение, а затем обнуляете ссылку. Операция CAS - это отдельная элементарная функция, которая не предлагает немедленного разрешения для опроса.

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

Итак, вы видите, что здесь происходит то, что поток удаления просто готовит новый поток опроса для обнуления ссылки. Попытка добиться неблокирующей функции удаления, я думаю, почти невозможна, потому что для этого потребуются три атомарные функции. Нулевое значение, указанное на нуль на указанный узел, и, наконец, новая ссылка от этого родительского узла на его преемника.

Чтобы ответить на ваш последний вопрос. Нет лучшего способа реализовать удаление и поддержание неблокирующего состояния очереди. По крайней мере, на этом этапе. Как только процессоры начнут выпускаться с 2-х и 3-х ходовым корпусом, это возможно.

9
ответ дан 4 December 2019 в 20:22
поделиться

Основная семантика очереди - добавление / опрос. Если вы используете poll () в ConcurrentLinkedQueue , он будет очищен должным образом. Основываясь на вашем описании, poll () должен дать вам удаление самой старой записи. Почему бы не использовать его вместо remove () ?

1
ответ дан 4 December 2019 в 20:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: