单例模式:
常用的软件设计模式之一,单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
简单理解:
- 只允许创建一个对象,节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等
- 单例的缺点 就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
单例模式的多种写法:
- 饿汉式:
/**
* 饿汉式单例模式
* (立即加载: 使用类的时候,已经把对象创建完毕)
* 优点: 实现简单,没有多线程同步问题
* 缺点: 使用类的时候会立即创建对象,无论后续是否使用,容易产生垃圾对象
*/
public class Singleton1 {
private static final Singleton1 instance = new Singleton1();
// 构造方法私有化
private Singleton1() {
}
// 静态方法返回该实例
public static Singleton1 getInstance() {
return instance;
}
}
- 懒汉式:
/**
* 懒汉式单例模式
* (延迟加载)
* 优点: 实现简单,当类被使用时, 对象实例未创建, 第一次使用对象实例时才会创建
* 缺点: 多线程环境中无法保证单例,线程不安全
*/
public class Singleton2 {
private static Singleton2 instance;
// 构造方法私有化
private Singleton2() {
}
// 静态方法返回该实例
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
- 线程安全的懒汉式(使用synchronize同步方法)
/**
* 懒汉式单例模式的优化,使用synchronize同步方法保证了多线程的安全
* 缺点: 使用同步方法会导致锁竞争,效率低
*/
public class Singleton3 {
private static Singleton3 instance;
// 构造方法私有
private Singleton3() {
}
// 静态方法返回该实例, 并使用synchronize关键字加同步锁,实现多线程情况下保证单例
public static synchronized Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
- 双锁检查单例(效率高, 线程安全且多线程操作原子性)
/**
* 单例模式的最佳实现,效率高,线程安全,且多线程操作原子性
*/
public class Singleton4 {
private static Singleton4 instance;
// 构造方法私有
private Singleton4(){
}
// 静态方法返回该实例
public static Singleton4 getInstance(){
// 第一次检查instance是否被实例化出来,进入if模块
if (instance == null) {
// 当有一个线程拿到了这个类的锁,再次检查instance是否被实例化出来
synchronized (Singleton4.class){
if (instance == null) {
instance = new Singleton4();
}
}
}
return instance;
}
}
- 内部类维护单例
/**
* 单例模式的其他实现, 不使用synchronize关键字, 使用内部类去维护单例的实例
*
* Singleton被加载时, 它的内部类SingletonHolder不会被加载,
* 只有getInstance方法被调用时,这个内部类才会被加载, 内部类加载完成之后才会有实例
*/
public class Singleton5 {
private Singleton5(){
}
public static Singleton5 getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static Singleton5 instance = new Singleton5();
}
}