Я не совсем понимаю, почему существует множество шаблонов реализации для двойной проверки блокировки (по-видимому, для обхода идиосинкразий компилятора в разных языках). Статья в Википедии на эту тему показывает наивный метод и возможные пути решения проблемы, но ни один не так прост (как на C #):
public class Foo
{
static Foo _singleton = null;
static object _singletonLock = new object();
public static Foo Singleton
{
get
{
if ( _singleton == null )
lock ( _singletonLock )
if ( _singleton == null )
{
Foo foo = new Foo();
// Do possibly lengthy initialization,
// but make sure the initialization
// chain doesn't invoke Foo.Singleton.
foo.Initialize();
// _singleton remains null until
// object construction is done.
_singleton = foo;
}
return _singleton;
}
}
В Java вы использовали бы synchronized () вместо lock (), но это в основном та же идея. Если существует возможное несоответствие того, когда назначается одноэлементное поле, то почему бы просто не использовать сначала локальную переменную и затем назначить одноэлементное поле в последний возможный момент перед выходом из критической секции? Я что-то упустил?
Есть аргумент @ michael-borgwardt, что в C # и Java статическое поле инициализируется только один раз при первом использовании, но , что поведение зависит от языка. И я часто использовал этот шаблон для ленивой инициализации свойства коллекции (например, user.Sessions).