Если конфликт не является фактором, блокировка (синхронизация) будет одним из вариантов, как вы упомянули, и может быть достаточно хорошим.
Однако, если есть споры, я вижу три основных варианта.
(1) каждый раз создавая его экземпляр
Просто создайте его как локальную переменную каждый раз, когда вы выполняете анализ. Локальные переменные тривиально безопасны. Инстанцирование, конечно, не бесплатно, но оно может быть приемлемым в зависимости от конкретной ситуации.
(2) с использованием локальных потоков
Если создание экземпляров оказывается дорогостоящим, рассмотрите возможность использования локальных потоков. Каждый поток будет сохранять свою собственную копию анализатора, и экземпляр анализатора будет повторно использоваться в данном потоке. Тем не менее, локальные потоки не без проблем. Локальные потоки нельзя собирать, если для них не задано значение null или пока не завершится удержание потока. Таким образом, существует проблема с памятью, если их слишком много. Во-вторых, остерегайтесь повторного использования. Если эти синтаксические анализаторы с состоянием, вам нужно убедиться, что вычистили и восстановили исходное состояние, чтобы последующее использование экземпляра threadlocal не страдало от побочного эффекта предыдущего использования.
(3) пул
Объединение в пул больше не рекомендуется, но если размеры объектов действительно велики, поэтому вам необходимо жестко ограничить число экземпляров, которые вы можете разрешить, тогда использование пула объектов может быть лучшим вариантом.