Я, вероятно, сделал бы это с двойной проверкой (т. Е. Проверить, если ноль; если ноль, заблокировать и проверить еще раз ; если все еще ноль, выполнить работу по компиляции и назначению) , Однако это в основном предотвращает дублирование работы при холодном запуске, чем что-либо еще.
Если работа была минимальной (т. Е. Меньше, чем компиляция), я мог бы использовать локальную переменную для выполнения работы, а затем использовать Interlocked.CompareExchange, чтобы назначить, если (и только если) поле все еще равно нулю. Это означает, что все потоки получают одинаковое значение, но могут означать дублирование (все, кроме первого, отбрасываются).
Если рассматриваемый сценарий вероятен, я бы на самом деле использовал инициализатор статического поля, так как он имеет меньше времени выполнения; замки не нужны.