单例模式
指的是在我们写的应用程序中需要保持类的实例有且只有一个,这种设计的实践就叫做单例模式;
为什么要使用单例模式
在一个应用中有些类通常我们需要高频次的调用,实例化,初始化,销毁等操作;
那么我们能不能实例化一次 初始化一次 之后直接调用呢,这种时候就要用单例模式了,减少了程序复杂度,降低了性能的开销,同时还增强了代码的健壮性,这简直是一举多得,一箭双雕;
单例模式应用场景
- 数据库连接池的设计,在一个应用中通常只需要一个数据库连接,应用所使用的连接池都是同一个;
- spring中所有的bean一般都是单例的,比如serveice dao;
其实在开发过程中我们一般不用自己实现单例模式;
作为java开发者spring中已经默认帮我们实现了单例模式,但作为一个有追求的开发工程师,明白原理才是我们应该做的;
实现一个单例模式
实现步骤
- 私有化成员变量
- 私有化构造方法,禁止使用new的方式创建实例;
- 提供统一的方法入口获取实例化对象;
单例模式要求:
- 懒加载: 需要用的时候才实例化,不需要的时候不占用内存;
- 线程安全 无需多说
- 效率高
饿汉式
饿汉式实现简单并且不存在并发问题
可以使用但是不推荐使用,因为没有按需加载,消耗内存空间
第一种实现
线程安全但是没有懒加载,可以这么使用,但是有更好的实现
/**
* 单例模式
* 饿汉式
*/
public class FastSingleton {
/**
* 静态属性
*/
private static FastSingleton fastSingleton = new FastSingleton();
// 私有化构造方法
private FastSingleton(){}
/**
* 获取实例的方法
* @return
*/
public static FastSingleton getInstance(){
return fastSingleton;
}
}
懒汉式
第一种实现,存在线程安全问题
存在线程安全问题,你要这么用就等着改bug吧
/**
* 单例模式1
* 懒汉式
*/
public class LazySingleton {
/**
* 私有成员变量
*/
private static LazySingleton lazySingleton;
// 私有化构造方法
private LazySingleton() {
}
/**
* 提供方法统一获取实例
*
* @return
*/
public static LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
第二种实现,synchronized处理线程安全问题
- 懒加载
- 线程安全
- 效率低 实例化以后,多线程同时获取实例存在线程竞争导致效率下降;
可以使用,没啥大问题
不推荐使用,有更好的实现
/**
* 单例模式
* 懒汉式
*/
public class LazySingleton2 {
/**
* 私有成员变量
*/
private static LazySingleton2 lazySingleton;
// 私有化构造方法
private LazySingleton2() {
}
/**
* 提供方法统一获取实例
*
* @return
*/
public static synchronized LazySingleton2 getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton2();
}
return lazySingleton;
}
}
第三种实现,synchronized双重锁校验解决并发问题和效率问题
解决了并发问题
也处理了效率问题
这下该没问题了吧
但是极端情况下还是存在问题,由于CPU指令重排序会出现偶发获取到未初始化的对象导致程序异常
/**
* 单例模式
* 懒汉式
*/
public class LazySingleton3 {
/**
* 私有成员变量
*/
private static LazySingleton3 lazySingleton;
// 私有化构造方法
private LazySingleton3() {}
/**
* 提供方法统一获取实例
*
* @return
*/
public static LazySingleton3 getInstance() {
if (lazySingleton != null) {
return lazySingleton;
}
synchronized (LazySingleton3.class) {
if (lazySingleton == null) {
lazySingleton = new LazySingleton3();
}
return lazySingleton;
}
}
}
完全体实现: 双重锁校验+volatile 防止指令重排序
- 懒加载 按需加载
- 双重锁校验优化性能
- volatile 防止指令重排序
推荐使用
/**
* 单例模式,完全体实现
* 懒汉式
*/
public class LazySingletonLast {
/**
* 私有成员变量
*/
private static volatile LazySingletonLast lazySingleton;
// 私有化构造方法
private LazySingletonLast() {
}
/**
* 提供方法统一获取实例
*
* @return
*/
public static LazySingletonLast getInstance() {
if (lazySingleton != null) {
return lazySingleton;
}
synchronized (LazySingletonLast.class) {
if (lazySingleton == null) {
lazySingleton = new LazySingletonLast();
}
return lazySingleton;
}
}
}