- public class Expensive {
- private static Expensive instance;
- private Expensive(){}
- public static Expensive getInstance() {
- if (instance == null) {
- instance = new Expensive();
- }
- return instance;
- }
- }
如果getInstance()處不使用synchronzied, 可能導致產生兩個singleton對象, 或者拿到半殘的instance對象。至於臭名昭著的DCL,那就更不必說了。
如果用synchronized, 那可能因爲鎖的原因在高併發下使性能受損。
最後一招似乎是不使用延遲加載,而是在類初始化時主動生成instance對象; 但是,如果生成這個對象確實很昂貴,而且又很有可能確實用不上它,那主動初始化豈不是很浪費?
《Java併發編程實踐》給出了致命一招:Initialization-on-demand holder,即把instance的初始化投入到一個內部類的初始過程中,就可以兼顧正確性和性能。
1. 內部類的初始化是延遲的,外部類初始化時不會初始化內部類。
2. 內部類的初始化是線程安全的,所以不用擔心兩個instance或半殘instance的問題。
3. 第一次獲取instance需要等它初始化,以後再獲取就不必了,而且也不需要鎖。所以在性能上也是妥妥的。
- public class Expensive {
- private Expensive(){}
- private static class LazyHolder {
- private static final Expensive instance = new Expensive();
- }
- public static Expensive getInstance() {
- return LazyHolder.instance;
- }
- }
更多介紹:http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom