Так, це необхідно. Існує кілька методів, які ви можете використовувати для досягнення безпеки потоку при ледачій ініціалізації:
Драконівська синхронізація:
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, додаткова синхронізація не потрібна.