Да, это необходимо. Есть несколько методов, которые можно использовать для обеспечения безопасности потоков с отложенной инициализацией:
Драконовская синхронизация:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Это решение требует, чтобы каждый поток был синхронизирован, в то время как на самом деле требуется только несколько первых.
Дважды проверьте синхронизацию :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Это решение гарантирует, что только первые несколько потоков, которые пытаются получить ваш синглтон, должны пройти через процесс получения блокировки.
Инициализация по запросу :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Это решение использует гарантии модели памяти Java при инициализации класса для обеспечения безопасности потоков. Каждый класс можно загрузить только один раз, и он будет загружен только тогда, когда это необходимо. Это означает, что первый раз getInstance
вызывается, InstanceHolder
будет загружен и instance
будет создан, и, поскольку это контролируется ClassLoader
s, никакой дополнительной синхронизации не требуется.