Я пытаюсь избежать критической области в многопоточности, потому что это ухудшает производительность!
Наоборот, улучшает производительность. Поскольку блокировка контейнерного класса может быть только очень мелкозернистой, необходимо получить блокировку для каждой простой операции. Это дорого. Когда вы заботитесь о блокировке, у вас есть возможность приобрести замок и выполнить много операций. Это не улучшает шансы на параллелизм, но значительно снижает накладные расходы блокировки. Вы можете выбрать наиболее подходящую для вашего приложения стратегию, которая не навязывается вам.
Добавьте к этому, что практически невозможно написать поточно-ориентированную реализацию контейнера, которая не является ни склонной к тупику, ни очень дорогой. Итераторы являются проблемой. Автор библиотеки должен выбирать между принятием блокировки на время жизни итератора (рискуя зайти в тупик) или обновлять все действующие итераторы, когда другой поток изменяет коллекцию (дорого). Только дорогой выбор безопасен. Опять же, вы выбираете наиболее разумную стратегию, дорогой выбор не навязывается вам.