JavaSE面试题之一:写一个Singleton
关于Singleton的说明
- 单例设计模式,即某个类在系统中只能有一个实例对象可被获取和使用的代码模式
- 例如:代表JVM运行环境的Runtime类
要点
- 某个类只能有一个实例
- 构造器私有化
- 必须自行创建这个实例
- 含有一个该类的静态变量来保存这个唯一实例
- 必须自行向整个系统提供这个实例
- 对外提供获取该实例对象的方式
- 直接暴露
- 用静态变量的get方法获取
- 对外提供获取该实例对象的方式
常见形式
-
饿汉式:直接创建对象,不存在线程安全问题
- 直接实例化(简洁直观)
/** * 饿汉式 * 直接创建对象,不管你是否需要这个对象都会创建 * 1.私有化构造器 * 2.自行创建,并用静态变量保存 * 3.向外提供这个实例(直接声明为public) * 4.强调这是一个单例,可以用final关键字修饰 */ public class Singleton { public static final Singleton INSTANCE = new Singleton(); private Singleton() { } }
- 枚举类型(最简洁)
/** * 枚举类型 * 表示该类型的对象是有限的几个 * 我们可以限定为1个,就成了单例 */ public enum Singleton { INSTANCE }
- 静态代码块饿汉式(适合复杂实例化)
下面是其一个实际应用场景public class Singleton { public static final Singleton INSTANCE; static { INSTANCE = new Singleton(); } private Singleton() { } }
public class Singleton { public static final Singleton INSTANCE; private String info; static { try { Properties properties = new Properties(); // 注意文件必须在src路径下才能加载 properties.load(Singleton.class.getClassLoader().getResourceAsStream("singleton.properties")); INSTANCE = new Singleton(properties.getProperty("name")); } catch (IOException e) { throw new RuntimeException(); } } private Singleton(String info) { this.info = info; } }
- 直接实例化(简洁直观)
-
懒汉式:延迟创建对象
- 线程不安全(适合于单线程)
/** * 懒汉式:延迟创建这个实例对象 * 1.构造器私有化 * 2.用一个静态变量保存这个唯一实例 * 3.提供一个静态方法,获取这个实例对象 * ! 以下代码线程不安全 */ public class Singleton { private static Singleton INSTANCE; private Singleton() { } public static Singleton getInstance() { if (INSTANCE == null) { INSTANCE = new Singleton(); } return INSTANCE; } }
- 线程安全(适用于多线程)
public class Singleton { private static Singleton INSTANCE; private Singleton() { } public static Singleton getInstance() { if (INSTANCE == null) { // 提升性能 synchronized (Singleton.class) { if (INSTANCE == null) { INSTANCE = new Singleton(); } } } return INSTANCE; } }
- 静态内部类形式(适用于多线程)
/** * 在内部类被加载和初始化时,才创建INSTANCE * 静态内部类不会随着外部类的加载和初始化而初始化,它是要单独加载和初始化的 * 该方法线程安全 */ public class Singleton { private Singleton() { } private static class Inner { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return Inner.INSTANCE; } }
- 线程不安全(适合于单线程)
小结
-
如果是饿汉式,那么枚举类方式最简洁
-
如果是懒汉式,静态内部类形式最简洁