概要
单例(Singleton)是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。
核心知识点如下:
(1) 将类的构造方法私有化(采用private修饰)。
(2) 在其内部产生该类的实例化对象,并将其封装成private static类型。
(3) 定义一个静态方法返回该类的实例
应用场景:配置文件、工具类、线程池、缓存、日志对象等
饿汉模式
public class Singleton {
// 构造函数私有化,不允许外部直接创建对象
private Singleton() {
};
// 创建类的唯一实例
private static Singleton instance = new Singleton();
// 提供了一个供外部访问本实例的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
- 优点:线程天生安全,不存在多线程同步问题,避免了synchronized所造成的性能问题;
- 缺点: 在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,
懒汉模式
//线程安全简单实现
public class Singleton {
//构造函数私有化,不允许外部直接创建对象
private Singleton(){
}
//声明类的实例,不实例化
private static Singleton instance;
//提供了一个供外部访问本实例的静态方法,在第一次调用此方法时才实例化对象
//synchronized为了解决线程不安全的问题,如果没有 synchronized,
//那么使用 getInstance()是有可能得到多个Singleton
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
- 优点:使用synchronized关键字避免多线程访问时,出现多个Singleton实例。相对于饿汉式在某些特定条件下会节约了内存。
- 缺点:同步方法频繁调用,效率略低影响性能;延迟加载,在第一次使用该单例的时候才会实例化对象出来。
单例模式最优方案
//线程安全 并且效率高
public class Singleton {
// 定义一个私有构造方法
private Singleton() {
}
//定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance
//变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用)
private static volatile Singleton instance;
//定义一个共有的静态方法,返回该类型实例
public static Singleton getInstance() {
// 对象实例化时与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率)
if (instance == null) {
//同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建)
synchronized (Singleton.class) {
//未初始化,则初始instance变量
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}