1、简介
懒汉式单例指的是在第一次调用时才创建单例对象。
它常用于资源紧张的场景,或者是需要延迟初始化单例对象的场景。
常见的懒汉式单例有两种创建方式:
非线程安全懒汉式
线程安全懒汉式
非线程安全的懒汉式单例只适用于单线程环境,而线程安全的懒汉式单例适用于多线程环境。
2、Non-thread safety
非线程安全懒汉式的实现方式如下:
1. public class LazySingleton { 2. private static LazySingleton instance; 3. private LazySingleton(){} 4. public static LazySingleton getInstance() { 5. if (instance == null) { 6. instance = new LazySingleton(); 7. } 8. return instance; 9. } 10. }
这种实现方式是非线程安全的,因为当多个线程同时调用getInstance()方法,会导致多次创建实例。
3、Thread safety
线程安全懒汉式实现方式就是在方法上加锁或者加同步代码块,这样就可以保证在多线程环境下只创建一个实例,如下所示:
1. public class LazySingleton { 2. private static LazySingleton instance; 3. private LazySingleton(){} 4. public static synchronized LazySingleton getInstance() { 5. if (instance == null) { 6. instance = new LazySingleton(); 7. } 8. return instance; 9. } 10. }
线程安全懒汉式的实现方式可以保证在多线程环境下只有一个实例被创建。但是,在第一次调用getInstance() 方法时,会出现线程阻塞的情况,可能会影响系统性能。
懒汉式单例模式适用于单例对象需要延迟初始化的情况,但在多线程环境下需要注意线程安全问题。
4、应用场景举例
一个典型的懒汉式单例模式在Java 中的应用是在配置文件管理类(Configuration(配置))中,如下所示:
1. public class Configuration { 2. private static Configuration instance; 3. private Properties config; 4. private Configuration(){ 5. config = new Properties(); 6. try { 7. config.load(this.getClass().getClassLoader().getResourceAsStream("config.properties")); 8. } catch (IOException e) { 9. e.printStackTrace(); 10. } 11. } 12. public static Configuration getInstance(){ 13. if(instance == null){ 14. instance = new Configuration(); 15. } 16. return instance; 17. } 18. public String getProperty(String key){ 19. return config.getProperty(key); 20. } 21. }
这个类管理着一个配置文件,配置文件在第一次被读取时,会被加载到Configuration 实例的 Properties 对象中。 以后的读取直接返回 Properties 对象中的值。 通过 getInstance()方法得到 Configuration 实例。
如上面的代码实现是线程安全的懒汉式单例,它保证了在多线程环境中仍然只有一个Configuration 实例存在,而且它使用了双重检查锁机制来保证在多线程环境下能够正确地创建单例对象。
另外一种常见的应用场景就是日志类,有些时候我们会希望在整个应用中都使用同一个日志类来管理日志信息,这时就可以使用懒汉式单例来创建日志类的实例,保证在整个应用中都使用同一个日志类。