单例模式定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
单例模式使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多资源,或者某种类型的对象应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如要访问 IO 和数据库等资源,这时就要考虑使用单例模式。
实现单例模式主要有如下几个关键点:
(1)构造函数不对外开放,一般为 private
(2)通过一个静态方法或者枚举返回单例类对象
(3)确保单例类的对象有且只有一个,尤其是在多线程环境下
(4)确保单例类对象在反序列化时不会重新构建对象
通过将单例类的构造函数私有化,使得客户端代码不能通过 new 的形式手动构造单例类对象。单例类会暴露一个公有静态方法,客户端需要调用这个静态方法获取到单例类的唯一对象,在获取这个单例对象的过程中需要确保线程安全,即在多线程环境下构造单例类的对象也是有且只有一个,这也是实现单例模式实现中比较困难的地方。
单例模式的实现方式
1、饿汉模式
饿汉模式的代码如下:
// Java 实现
public class Singleton {
private static Singleton instance = new Singleton();
/**
* 构造私有函数
*/
private Singleton() {
}
/**
* 公有的静态函数,对外暴露获取单例对象的接口
*/
public static Singleton getInstance() {
return instance;
}
}
//Kotlin实现
object Singleton
Kotlin的对象声明,在Kotlin 中类没有静态方法。如果需要写一个可以无需用一个类的实例来调用,但需要访问类内部的函数(如:工厂方法,单例等),可以把该类声明为一个对象。该对象与其他语言的静态成员是类似的。
对象声明的初始化过程是线程安全的
饿汉模式代码比较简单,对象在类中被定义为 private static,通过 getInstance(),通过 Java 的 ClassLoader 机制保证了单例对象唯一。
instance什么时候被初始化?
Singleton 类被加载的时候就会被初始化,java虚拟机规范虽然没有强制性约束在什么时候开始类加载过程,但是对于类的初始化,虚拟机规范则严格规定了有且只有四种情况必须立即对类进行初始化,遇到new、getStatic、putStatic或invokeStatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。 生成这4条指令最常见的java代码场景是:
1)使用new关键字实例化对象
2)读取一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)
3)设置一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)
4)调用一个类的静态方法
class的生命周期?
class的生命周期一般来说会经历加载、连接、初始化、使用、和卸载五个阶段