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