Giriş
Eğer multi thread ortamda lazy singleton kullanmak istersek şöyle yaparız. Nesne volatile tanımlanmalıdır! Volatile tanımlanınca "partially initialized object" sıkıntısı olmuyor. Yani
single == null kontrolü ve single = new ... satırları yer değiştirmiyor.
Örnek
Şöyle yaparız
public class Singleton { private static volatile Singleton _instance; // volatile variable public static Singleton getInstance() { if (_instance == null) { synchronized (Singleton.class) { if (_instance == null) _instance = new Singleton(); } } return _instance; } }
Örnek
Şöyle yaparız. Nesne volatile tanımlanmalıdır! Volatile tanımlanınca "partially initialized object" sıkıntısı olmuyor. Yani
single == null kontrolü ve single = new ... satırları yer değiştirmiyor.
class MultithreadedSingle {
private static volatile MultithreadedSingle single;
private MultithreadedSingle() {
}
public static MultithreadedSingle getInstance() {
if(single==null){
synchronized(MultithreadedSingle.class){
if(single==null){
single= new MultithreadedSingle();
}
}
}
return single;
}
}
Eğer lock olarak sınıfı kullanmak istemezsek şöyle yaparız.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;
}
Şimdi niçin synhronized kelimesinden sonra ikinci defa null kontrolü yaptığımıza bakalım.if (_instance == null) { // L1
synchronized (Singleton.class) { // L2
if (_instance == null) { // L3
_instance = new Singleton();// L4
}
}
}
Eğer ikinci defa null kontrolü yapmazsak iki thread şöyle çalışır. Yani bloke olan ikinci thread, synchronized bloğa girince, birinci thread'in yaptığı işi kontrol etmezse, yeni bir nesne yaratır1. Thread 1 L1'e gelir ve _instance null'dırDolayısıyla hata olur. synchronized kelimesinden sonra ikinci null kontrolü Thread 2'nin yeni bir instance yaratmasını engeller. İşte bu yüzden ismi "Double Checked"
2. Thread 2 L1'e gelir ve _instance null'dır
3. Thread 1 L2'de mutex'i kilitler
4. Thread 2 L2'de mutex'i kilitlemeye çalışır ama bloke olur
5. Thread 1 yeni bir instance yaratır ve L4'te atar
6. Thread 1 L2'de kilitlediği mutex'i bırakır
7. Thread 2 L2'de mutex'i kilitler
8. Thread 2 yeni bir instance yaratır ve L4'te atar
9. Thread 2 L2'de kilitlediği mutex'i bırakır
Yanlış bir kod şöyle
class SharedObject {
private static final Object LOCK = new Object(); //Volatile değil
private static SharedObject instance = null;
public static SharedObject retrieve() {
if (instance == null) {
synchronized (LOCK) {
//Burada ikinci null kontrolü yapılmıyor
instance = create();
}
}
return instance;
}
private static SharedObject create() {
return new SharedObject();
}
}
Hiç yorum yok:
Yorum Gönder