Java设计模式之《单例模式》

单例模式是应该是设计模式里面最简单的一种模式了,我也从单例模式开始,开启设计模式之旅。

定义:Ensure a class has only one instance, and provide a global point of access to it.确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

简单来说,单例对象的类必须保证只有一个实例存在。

应用场景

  • Windows的任务管理器就是很典型的单例模式,想想看,你能打开两个任务管理器吗?
  • Windows的回收站也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  • 网站的计数器,一般也是采用单例模式实现。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
  • 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

单例模式类图:

单例模式三要素:

  • 私有的构造方法;
  • 指向自己实例的私有静态引用;
  • 以自己实例为返回值的静态的公有方法。

懒汉模式:

package com.clarezhou.singleton;

public class LangHanSingleton {
	//定义一个私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,而要使用提供的公共方法来获取
    private static LangHanSingleton lhs = null;
    //定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建
    private LangHanSingleton(){}
    //定义一个公共的公开的方法来返回该类的实例,由于是懒汉式,需要在第一次使用时生成实例,所以为了线程安全,使用synchronized关键字来确保只会生成单例
    public static synchronized LangHanSingleton getInstance(){
        if(lhs == null){
        	lhs = new LangHanSingleton();
        }
        return lhs;
    }
}

此模式单线程是安全的,但是多线程的情况下可能会同时创建多个实例对象,所以我们在getInstance公共方法上加了synchonized同步锁,因此多线程的情况下每次都需要进行同步,开销就加了不少。

饿汉模式(推荐):

package com.clarezhou.singleton;

public class EHanSingleton {
    //此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中
    private static EHanSingleton ehs = new EHanSingleton();
    //定义无参构造器
    private EHanSingleton(){}
    //定义公开方法,返回已创建的单例
    public static EHanSingleton getInstance(){
        return ehs;
    }
}

此模式是线程安全的,而且在类加载的同时会创建实例对象,反应速度较快。

双重检测:

package com.clarezhou.singleton;

public class DoubleSingleton {
	 //定义一个私有类变量
	 private static DoubleSingleton ds = null;
	 //定义无参构造器
	 private DoubleSingleton(){}
	 ///定义公开方法
	 public static DoubleSingleton getInstance(){
        if(ds == null){
            synchronized (DoubleSingleton.class) {
                if(ds == null){
                    ds = new DoubleSingleton();
                }
            }
        }
        return ds;
    }
}

双重检测较好的解决了懒汉模式开销大的问题,但首次加载的时候效率依然较低。

静态内部类方式:

package com.clarezhou.singleton;

public class InsideSingleton {
	//定义内部类
	public static class SingletonHolder{
        private static InsideSingleton ins = new InsideSingleton();
    }
	//定义无参构造器
    private InsideSingleton(){}
    //公共方法
    public static InsideSingleton getInstance(){
        return SingletonHolder.ins;
    }
}

加载外部类的时候,并不会同时加载其静态内部类,只有在发生调用的时候才会进行加载,加载的时候就会创建单例实例并返回,有效实现了懒加载(延迟加载),至于同步问题,我们采用和饿汉式同样的静态初始化器的方式,借助JVM来实现线程安全。

猜你喜欢

转载自blog.csdn.net/zhoukun1314/article/details/87954749