单例模式(Singleton Pattern)属于创建型模式
概述
单例就是只有一个实例对象,即在整个程序中,同一个类始终只有一个对象进行操作。这样可以极大的减少内存开支和系统的性能开销,因此应用十分广泛。比如数据库连接类,实际上只需要创建一个对象或是直接使用静态方法就可以了,没必要去创建多个对象。
这种模式提供了一种创建对象的最佳方式,让类负责创建自己的对象,同时确保只有单个对象被创建。这个类需要提供访问其唯一对象的方式,且可以直接访问,不需要实例化该类的对象。
注意点:
- 为保证只能由自己创建对象,单例类必须构造方法私有化。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
经过多年的演进,单例模式有诸多实现方式,下面逐个介绍。
代码实现
饿汉式
饿汉式单例是最普通的单例模式写法,由于在类加载时就创建对象,保证了线程的安全。这种方式比较常用,但容易产生垃圾对象,对空间的消耗较大。
public class Singleton {
/**
* 单例模式的核心,构造方法私有化
*/
private Singleton() {
}
/**
* 用于全局引用的唯一单例对象,在一开始就创建好
*/
private final static Singleton INSTANCE = new Singleton();
/**
* 获取全局唯一的单例对象
* @return 实例对象
*/
public static Singleton getInstance() {
return INSTANCE;
}
}
这种方式最大的问题就是浪费内存,因为创建的对象程序不一定用得到,如果创建了没用到,就是一种浪费。这种方式由于不存在线程安全问题, 因此不用加锁,效率较高,以空间换时间。
想要避免这种浪费,自然就想到在使用的时候才创建对象,这样就诞生了懒汉式。
懒汉式
普通
懒汉式单例就是在类加载时不创建对象,用到的时候才创建对象。
public class Singleton {
/**
* 单例模式的核心,构造方法私有化
*/
private Singleton() {
}
/**
* 在一开始先不进行对象创建
*/
private static Singleton INSTANCE;
/**
* 获取全局唯一的单例对象
* @return 单例对象
*/
public static Singleton getInstance() {
// 如果实例为空,那么就进行创建,不为空说明已经创建过了,就直接返回,保证单例
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
这种方式最大的问题就是在多线程情况下不安全,比如这样调用:
for (int i = 0; i < 10; i++) {
new Thread(()->{
Singleton.getInstance();
}).start();
}
多线程环境下,非空判断容易失效,造成创建多个实例,违背了单例的初衷。为了避免这一问题,就不得不加锁,这样效率就会降低,以时间换空间。
为了避免线程安全问题,还得进行一些改进:
// 方法添加 synchronized 关键字加锁
public static synchronized Singleton getInstance(){
if(INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
既然多个线程要调用,那么就直接加一把锁,在方法上添加 synchronized 关键字即可,这样同一时间只能有一个线程进入了。
虽然这样简单粗暴,但是在高并发的情况下,效率肯定是比较低的,可以再进行优化:
public static Singleton getInstance(){
// 规避多线程情况
if(INSTANCE == null) {
// 只对赋值这一步进行加锁,提升效率
synchronized (Singleton.class) {
INSTANCE = new Singleton();
}
}
return INSTANCE;
}
不过这样还不完美,因为这样还是有可能多个线程同时判断为 null 而进入等锁的状态。
所以,还得加一层内层判断:
public static Singleton getInstance(){
if(INSTANCE == null) {
synchronized (Singleton.class) {
// 内层检测以实现单例
if(INSTANCE == null) {
Java单例模式详解:饿汉式、懒汉式与枚举实现

最低0.47元/天 解锁文章
5367

被折叠的 条评论
为什么被折叠?



