Является ли подсчет ссылок хорошим дизайном - PullRequest
1 голос
/ 04 августа 2011

Мы работаем над контейнером приложений, который использует подсчет ссылок в качестве механизма для отслеживания полученных запросов и отправленных ответов. Счетчик ссылок используется для обеспечения возможности постепенного отключения контейнера, т. Е. if (refCount == 0) shutdown;

Счетчик ссылок увеличивается для каждого запроса, а также для ожидающего ответа. Счетчик ссылок уменьшается только после того, как приложение приняло запрос, а также только после того, как приложение отправило действительный ответ. Итак, вот мой вопрос: является ли подсчет ссылок хорошим проектным решением в этом сценарии, скажем, по сравнению с сохранением RequestContext, которое закрывается, только когда приложение / контейнер отправило ответ?

Поскольку программное обеспечение реализовано на Java, я рассматривал другие варианты на Java и наткнулся на эту статью, http://weblogs.java.net/blog/2006/05/04/understanding-weak-references, которая заставила меня подумать, что попытка использовать ReferenceQueue может быть другим подходом для этого.

Ответы [ 2 ]

1 голос
/ 04 августа 2011

Обратите внимание, что вы будете платить за этот счетчик с хитами производительности.Фактически вам требуется барьер памяти для каждого запроса, если вы используете параллельные потоки для обслуживания запросов.(Инструкция по барьеру памяти обычно стоит до ~ 200 инструкций.)

По вашему вопросу также кажется, что вам даже не нужен счетчик, а скорее двоичный флаг, который указывает, есть ли какие-либо активные запросы, например,requestsInProgress флаг.Идея состоит в том, что вы «корректно завершаете работу», когда значение флага равно false.

Если ваш контейнер в основном предоставляет конечные точки сети, например REST / HTTP, тогда я настоятельно рекомендую вам рассмотреть NIO и использовать однопоточный механизм диспетчеризации длялинеаризовать req / rep на периферии контейнера.(Вы можете поставить их в очередь и развернуть в N потоков обработки, используя параллельные очереди в java.util.concurrent.

[NIO subsystem] <-{poll}-[Selector(accept/read)/dispatch thread] => [Q:producer/consumer pattern 1:N]
[NIO subystem] <-{poll}-[Selector(write)/responder thread] <= [Q:producer/consumer N:1]

Преимущество?

Если вы используете один и тот же поток для отправки и ответчика, то памяти нетБарьеры задействованы - поток будет прикреплен к ядру, а ваш флаг будет эксклюзивным для его строки кэша:

например

после запроса очередей отправки: инкремент req_in_progress

после того, как ответчик удаляет ответ: декремент req_in_progress

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

Если производительность вообще не является проблемой, то почему бы просто не использовать AtomicInteger для счетчика и поместить его в глобальный контекст?

1 голос
/ 04 августа 2011

Это действительно очень хороший способ сделать это.Вам также следует дополнительно использовать ThreadLocal (Если ваш конвейер запроса-ответа будет обрабатываться одним потоком)

По сути, при получении запроса.Установите ThreadLocal с WeakRefernce для вашего объекта запроса (или некоторого атрибута запроса, такого как идентификатор пользователя и т. Д.).Затем вы можете get() объект в любом месте вашего конвейера обработки.

Если вы используете ThreadPool рабочих для обработки запроса, убедитесь, что вы удалили объект Weak Reference из ThreadLocal вашего потока, чтобы больше не было ссылок на этот объект.Если вы создаете новый поток для каждого запроса, вам даже не нужно этого делать.Когда поток умирает, объект будет автоматически возвращен в referenceQueue (так как действительная ссылка не указывает на этот объект)

...