前言
本博客介绍一种创建型模式:单例模式
这是一种比较容易理解的设计模式,可以理解为创建对象的一种很好的做法。可以尽量避免创建过多的对象,给JVM造成很大的负载。
应用场景
单例模式的一些应用场景:
1、比如数据连接类,这是需要经常调用的
2、网站访问量统计的服务类,需要多次调用
3、导出导入Excel表,一些业务复杂的系统需要多次调用
...
总结起来就是需要经常调用的通用类,我们可以用单例模式进行很好的设计。
编程思想
单例模式涉及了两种重要的编程思想:懒加载思想和缓存思想
缓存思想:
private static Singleton instance = null;//先放内存缓存
public static Singleton getInstance() {
if (instance == null) {//内存加载不到,创建对象
instance = new Singleton();
}
return instance;//内存缓存有,直接调用
}
懒加载思想:
下面例子就是懒加载的简单应用,创建一个对象都是需要用的时候实例,尽量不要在加载类的时候就实例了,这种方法可以很好的避免给JVM增加负载。这是一种很好的编程习惯。
public static Singleton getInstance() {
if (instance == null) {//对象需要用时才实例
instance = new Singleton();
}
return instance;
}
单例模式实例
下面介绍几种常用的单例模式实例
1、懒汉模式
这是一种线程不安全,懒加载的方式
public class Singleton {
private static Singleton instance;
//定义private构造函数,使类不可以被实例
private Singleton (){}
/**
* 懒汉模式,线程不安全,懒加载
* @return
*/
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
上面例子线程不安全,要线程安全可以加个同步锁,不过加了同步锁性能又不好了,加载慢
public class Singleton {
private static Singleton instance;
//定义private构造函数,使类不可以被实例
private Singleton (){}
/**
* 懒汉模式,线程安全,懒加载
* @return
*/
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2、饿汉模式
下面介绍一下单例模式的另外一种实现方式,饿汉模式
其实现原理就是在类内部全局new一个对象,利用Java虚拟机的类加载机制,保证了线程安全,不过很明显,一创建了,就实例了单例类,会给JVM增加负载
public class Singleton {
//定义private构造函数,使类不可以被实例
private Singleton (){}
//加载类的时候,利用JVM的类加载机制创建对象,保证了线程安全,但是效率不好
private static Singleton instance = new Singleton();
/**
* 饿汉模式,线程安全,非懒加载
* @return
*/
public static Singleton getInstance() {
return instance;
}
}
3、双检锁/双重校验锁(DCL,即 double-checked locking)
下面介绍一种双检锁的实现方式,这种方式看起来稍稍比较复杂了点,不过可以实现线程安全,同时双检锁的方式可以保证性能比较高
public class Singleton {
//定义private构造函数,使类不可以被实例
private Singleton (){}
private volatile static Singleton instance;
/**
* 双检锁/双重校验锁(DCL,即 double-checked locking)线程安全,懒加载
* @return
*/
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
4、登记式/内部类
下面用内部类的方式来实现单例模式,这种方式可以和饿汉模式来对比一下
这种方式和刚才介绍的饿汉模式类似,不过区别就是做到了懒加载,我们可以分析例子。方法就是在单例类里加个内部类,这样做就不会像饿汉模式一样,单例类一加载就实例对象。当调用getInstance方法的时候,才会调用,创建对象。这样就做到了懒加载,同时也是利用JVM保证了线程安全
public class Singleton {
//定义private构造函数,使类不可以被实例
private Singleton (){}
public static class SingletonHolder{
private final static Singleton INSTANCE = new Singleton();
}
/**
* 登记式/静态内部类,线程安全,懒加载
* @return
*/
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
5、枚举模式
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
/**
* 枚举方式
*/
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}