оптимальный пул потоковых объектов Java - PullRequest
4 голосов
/ 07 января 2012

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

Первая необходимость заключается в том, чтобы с конечным набором ключей String мне сначала нужно было искать, в противном случае создать и опубликовать дорогой объект. Это подразумевает один глобальный мьютекс на наивной реализации. Есть что-то лучше?

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

Конечно, для 2 мьютексов я могу абсолютно минимизировать время, затрачиваемое в синхронизированном выражении, но я ищу что-то лучшее в обоих случаях. Может быть, есть неблокирующее решение для обоих?

Andy

Ответы [ 4 ]

1 голос
/ 07 января 2012

Для первой части: вместо того, чтобы помещать дорогие объекты непосредственно в HashMap, вместо этого создайте простую обертку, которая дешева в создании. Затем вы в основном создаете дорогой объект по требованию в методе wrappers getExpensiveObject() - хотя, очевидно, можно запустить его мгновенно, если это предпочтительнее. В любом случае вам нужно синхронизировать метод get, но это можно сделать дешево с двойной проверкой блокировки - обычно мы просто заменяем нормальное чтение на энергозависимое чтение и используем дорогую синхронизацию только при создании объекта.

Предполагается, что вы используете виды ConcurrentHashMap, поскольку нам нужен putIfAbsent или какой-то эквивалентный метод для этого (мы не хотим заменять существующий дорогой объект нашей пустой оболочкой)

Нет времени думать о второй проблеме сейчас, может позже.

0 голосов
/ 08 января 2012

Я думаю, что у меня есть ответ после того, как я подумал:

ПРИМЕЧАНИЕ: мой ответ зависит от того факта, что фабрика идемпотентна по отношению к его ключу String, а рабочие все идемпотентны относительно своей фабрики, что можетне было очевидно из вопроса.

Для первой глобальной хэш-карты на основе одноэлементного ключа я использую идею о том, что хэш-карта никогда не имеет удалений.Только новые идемпотентные.Поэтому я использую volatile ссылку на hashmap и получаю текущую карту из переменной volatile singleton без мьютекса.(изменчивые выборки ссылок в Java теперь очень дешевы). Если карта устарела, в том смысле, что в ней нет всех существующих фабрик, это нормально.Потому что, если у него есть фабрика (обычно она разогревается), я ее получу.Только стоимость летучих получить.Если у него его нет, я сейчас сверяюсь с живой картой, чтобы получить доступ к мьютексу для «живой» карты.Если я получу фабрику с карты сейчас (маловероятно), я получу ее.В противном случае, я сейчас делаю очень дорогую операцию по созданию фабрики (вне мьютексов).Когда я закончил, я вернулся к живой карте с мьютексом, и из-за того, что другой поток делал то же самое, он может быть там сейчас!Так что, если на карте есть фабрика, я выбрасываю потраченную впустую фабрику и использую ту, которая была поставлена ​​передо мной.В противном случае я добавляю новую фабрику на карту, оставляю мьютекс и начинаю использовать фабрику.

Не думаю, что для этого есть что-то лучше.

На заводской софт-кеш, я думаюЯ просто хочу использовать ConcurrentLinkedQueue.Тем не менее, мои элементы будут ссылками на softreferences.Поэтому я извлекаю из ConcurrentLinkedQueue объект, который имеет ссылку на мягкую ссылку на самого работника.Возможно, рабочий был освобожден, поэтому я просто снова создаю рабочий на фабрике, воссоздаю мягкую ссылку в объекте, полученном из ConcurrentLinkedQueue, и устанавливаю мягкую ссылку на рабочего.Так что нет никакого мьютекса для получения работника с завода, только извлечение ConcurrentLinkedQueue, и ссылки на работника мягкие.

0 голосов
/ 07 января 2012

Сначала мне нужно поискать, иначе создайте и опубликуйте дорогой объект.

Нет неблокирующего решения для этого. Существует неблокирующая карта с get и put, если она отсутствует, но для этого требуется предварительно вычислить значение put, чего нельзя сделать с дорогим объектом.

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

0 голосов
/ 07 января 2012

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

...