使用场景:在容器中一个对象只存在一个实例。
目的:1.防止堆中内存过多。影响效率。
2.无论怎么使用,都规定使用同一个对象
实例:获取序列号,任务管理器,计数器等
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
代码:
1.饿汉式(线程安全,调用效率高,但是不能延时加载,会占用内存)
1. public class Singleton { 2. private static Singleton instance = new Singleton(); 3. private Singleton (){} 4. public static Singleton getInstance() { 5. return instance; 6. } 7. }
2.懒汉式(线程安全,调用效率不高,但是能延时加载)
1. public class Singleton { 2. private static Singleton instance; 3. private Singleton (){} 4. public static synchronized Singleton getInstance() { 5. if (instance == null) { 6. instance = new Singleton(); 7. } 8. return instance; 9. } 10. }
3.双检锁/双重校验锁 延时加载 比较复杂 不建议使用
1. public class Singleton { 2. private volatile static Singleton singleton; 3. private Singleton (){} 4. public static Singleton getSingleton() { 5. if (singleton == null) { 6. synchronized (Singleton.class) { 7. if (singleton == null) { 8. singleton = new Singleton(); 9. } 10. } 11. } 12. return singleton; 13. } 14. }
4.静态内部类 延时加载 只适用于静态域的情况
1. public class Singleton { 2. private static class SingletonHolder { 3. private static final Singleton INSTANCE = new Singleton(); 4. } 5. private Singleton (){} 6. public static final Singleton getInstance() { 7. return SingletonHolder.INSTANCE; 8. } 9. } 10.
5.枚举 非延时加载
1. public enum Singleton { 2. INSTANCE; 3. public void whateverMethod() { 4. } 5. }
一般情况下,建议使用饿汉模式,只有在要明确实现 lazy loading 效果时,才会使用第静态内部类方式。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。