ใช่มันเป็นสิ่งที่จำเป็น มีหลายวิธีที่คุณสามารถใช้เพื่อให้เกิดความปลอดภัยของเธรดด้วยการเริ่มต้นแบบขี้เกียจ:
การซิงโครไนซ์ Draconian:
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 จึงไม่จำเป็นต้องซิงโครไนซ์เพิ่มเติม