简介
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,它提供了一种创建对象的最佳方式。
单例模式的特点是该类只能有一个对象(实例),使用者通过该类提供的静态方法获得这个实例,用于当某个类只需要或只能有一个实例时,如配置文件等。和静态类(静态方法)类似,两者的不同:静态类和单例模式区别
实现
单例模式的实现要点是:
- 将构造方法定义为私有,防止外部通过new创建实例
- 定义获取唯一实例的公有静态方法,一般名为:public static 类名 getInstance()
- 同时将实例变量定义为静态,以便静态的获取实例方法获取
单例模式的实现根据实例是在类加载时创建还是第一次调用时创建,可分为“饿汉式”和“懒汉式”。
在类加载时就创建实例的“饿汉式”缺点为没有lazy loading的效果,从而降低内存的使用率,而在获得实例的方法内部通过判空创建的一般“懒汉式”,对象实例有可能被多个线程多次创建,线程不安全。
所以推荐的实现方法有 使用静态内部类的懒汉模式 和 使用双重校验锁的懒汉模式。
使用静态内部类的懒汉模式
该模式通过建造静态内部类,并在内部类中定义静态对象获得实例,由于静态内部类的特性,只有在其被第一次引用的时候才会加载,所以实现了lazy loading,同时也是线程安全的。
public class Student {
// 将构造方法定义为私有,防止外部通过new创建实例
private Student() {}
/**
* 实例持有者(静态内部类)
*/
public static class holder {
// 实例声明为静态常量,引用不可更改
private static final Student INSTANCE = new Student();
}
// 获取唯一实例的公有静态方法
public static Student getInstance() {
return holder.INSTANCE;
}
public String toString() {
return "这是唯一的实例";
}
public static void main(String[] args) {
// 因为构造方法为私有,下行语句无效
// Student student = new Student();
//正确获取实例方法
Student student = Student.getInstance();
System.out.println(student.toString());
}
}
使用双重校验锁的懒汉模式
该模式首先需要将实例变量加上volatile修饰符,volatile能保证对象的可见性,在工作内存中的内容更新能立即在主内存中可见。在获取实例方法中判空,并使用synchronized关键字加锁,加锁后再一次判空。
之所以进行两次判空,第一次是因为多数情况下实例已经被创建,总是进入加锁语句会多余浪费时间降低效率,第二次是为防止在第一次判空之后、加锁之前的空当资源被占用并new出对象,两次判空兼具了效率和安全
public class Student {
private volatile static Student instance;
// 将构造方法定义为私有,防止外部通过new创建实例
private Student() {}
// 获取唯一实例的公有静态方法
public static Student getInstance() {
// 双重校验锁
if (instance == null) {
synchronized (Student.class) {
if (instance == null) {
instance = new Student();
}
}
}
return instance;
}
public String toString() {
return "这是唯一的实例";
}
public static void main(String[] args) {
// 因为构造方法为私有,下行语句无效
// Student student = new Student();
//正确获取实例方法
Student student = Student.getInstance();
System.out.println(student.toString());
}
}