一、介绍
所谓类的单例设计模式,就是采用一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
如Hibernate的SessionFactory,一般情况下,一个项目只需要一个SessionFactory,此时就可以用到单例模式。
二、实现
2.1 饿汉式
/**
* @Note {饿汉式 使用静态变量实现}
* @author giserDev
* @Date 2020-05-09 22:43:24
*/
class Singleton {
// 1. 私有化构造函数
private Singleton() { }
// 2.创建实例对象
private static final Singleton instance = new Singleton();
// 3.提供一个公有静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
说明:
1)优点 :写法简单,就是在类装载的时候就完成实例化,避免了线程同步问题;
2)缺点:在类装载时就完成实例化,没有达到懒加载效果。如果这个实例一直没有被用到,则会造成内存浪费。
3)这种方式是基于ClassLoader机制,避免了多线程同步问题,在类装载的时候实例化,但是导致类装载的原因较多,没有达到lazy loading效果。
4)这种单例模式可用,简单,但是可能造成内存浪费。
2.2 Double-Check
/**
* @Note {双重校验}
* @author giserDev
* @Date 2020-05-09 23:38:50
*/
class Singleton {
private static volatile Singleton instance;
private Singleton () {
}
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
说明:
线程安全、延迟加载、节约内存、效率较高。
2.3 静态内部类
/**
* @Note {静态内部类}
* @author giserDev
* @Date 2020-05-09 23:38:50
*/
class Singleton {
// 私有化构造函数
private Singleton () {}
// 静态内部类
private static class SingletonFactory {
public static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonFactory.INSTANCE;
}
}
说明:
a)在外部类Singleton加载时内部类不会被加载,只有在使用时才会加载内部类,实现了lazy load;
b)类的静态属性只会在第一次加载类的时候初始化一次,保证了只有唯一的实例对象;
c)在内部类SingletonFactory加载时会实例化INSTANCE,由于类初始化时,别的线程无法进入, 因此是线程安全的,因此实例化也是线程安全的。
2.4 使用枚举
/**
* @Note {枚举实现单例
* 可以避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
* }
* @author giserDev
* @Date 2020-05-10 00:07:40
*/
enum Singleton {
INSTANCE;
public void sayHello() {
System.out.println("OK");
}
}
三、jdk源码
/**
* Every Java application has a single instance of class
* <code>Runtime</code> that allows the application to interface with
* the environment in which the application is running. The current
* runtime can be obtained from the <code>getRuntime</code> method.
* <p>
* An application cannot create its own instance of this class.
*
* @author unascribed
* @see java.lang.Runtime#getRuntime()
* @since JDK1.0
*/
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
// 其它省略
}
四、细节说明和注意事项
- 单例模式保证了系统内存中该类只存在一个对象实例,节省了系统资源,对于一些需要频繁创建和销毁的对象使用单例模式可以提高系统性能。
- 当实例化单例类时,必须使用响应的获取单例对象的方法。
- 单例模式使用的场景:
a、需要频繁进行对象的创建和销毁时;
b、创建对象消耗资源很大时,即重量级对象,但又经常使用的对象,如工具类对象,数据库访问对象,如数据源、sessionFactory等。