java 延迟初始化_Java并发编程——延迟初始化占位类模式
——僅作筆記使用,內(nèi)容多摘自《java并發(fā)編程實戰(zhàn)》
在并發(fā)編程中,如果狀態(tài)變量僅在單個線程中初始化和使用,自然是線程安全的,但一旦涉及到線程間的數(shù)據(jù)交互,如何聲明一個用于多線程的單例狀態(tài)變量才是安全的呢?最容易想到的,自然是通過一個工廠函數(shù)進行初始化并獲取實例對象,如下:
public class Demo {
private static Resource resource;
public static Resource getInstance() {
if(resource == null) {
resource = new Resource();
}
return resource;
}
}
然而上述的方法存在一個典型的競態(tài)條件,在多線程的形況下getInstance可能會返回不同的對象,導致不可預知的錯誤。因此需要進行同步操作:
public class Demo {
private static Resource resource;
public synchronized static Resource getInstance() {
if(resource == null) {
resource = new Resource();
}
return resource;
}
}
然而,眾所周知的是,通過同步限制線程同時訪問方法,會一定程度上影響程序的并發(fā)性能,于是產(chǎn)生了以下的初始化方法:
public class Demo {
public static Resource resource= new Resource();
public static Resource getInstance() {
return resource;
}
}
因為在初始化器中采用了特殊的方式處理靜態(tài)域,并提供了額外的線程安全性保證。靜態(tài)初始化器是由JVM在類的初始化階段執(zhí)行,即在類被加載后并且被線程使用之前。由于JVM在初始化期間將獲得一個鎖,且每個線程都至少獲取一次這個鎖以確保這個類已經(jīng)加載,故在靜態(tài)初始化期間,內(nèi)存寫入操作將自動對所有的線程可見,以及避免數(shù)據(jù)破壞。
簡言之,類中的靜態(tài)變量在聲明的時候就做初始化,可以經(jīng)由JVM提供線程安全方便的保證,而無需自己添加synchronized關(guān)鍵字去進行同步,從而減少了線程同步帶來的性能消耗。這種初始化方式被稱為提前初始化。相對的,之前兩種初始化方式,被稱為惰性初始化或者延遲初始化。
考慮到有些類的實例在初始化的時候,可能會產(chǎn)生比較高的開銷,故人們希望在需要用到的時候再進行初始化,于是結(jié)合延遲初始化域JVM初始化靜態(tài)域的特點,產(chǎn)生了較為常用的延遲初始化占位類模式:
public class Demo {
private static class ResourceHolder {
public static Resource resource = new Resource();
}
public static synchronized Resource getInstance() {
return ResourceHolder.resource;
}
}
因為靜態(tài)類在使用的時候才會被加載,故JVM第一次加載該靜態(tài)類的時候,通過JVM即可實現(xiàn)靜態(tài)域的線程同步,即滿足了延遲加載的需求,也避開了同步帶來的性能消耗。
總結(jié)
以上是生活随笔為你收集整理的java 延迟初始化_Java并发编程——延迟初始化占位类模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机淘宝页面电脑版(电脑端手机淘宝)
- 下一篇: java方法2数据求和_Leet Cod