1定义
单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。
2 当例模式结构图
3 代码实现
1)饿汉式单例模式
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton(){}
public static EagerSingleton getInstance(){
return instance;
}
}
2)懒汉式单例模式
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton(){}
//synchronized 导致性能低下
synchronized public static LazySingleton getInstance(){
if(instance==null){
instance = new LazySingleton();
}
return instance;
}
public static LazySingleton getInstance1(){
if(instance==null){
// 线程不安全,可能会产生多个实例
synchronized(LazySingleton.class){
instance = new LazySingleton();
}
}
return instance;
}
/**
* 此时需要在instance前volatile,被volatile修饰的成员变量可以确保多个线程都能够正确处理,且该代
* 码只能在JDK 1.5及以上版本中才能正确执行。由于volatile关键字会屏蔽Java虚拟机所做的一
* 些代码优化,可能会导致系统运行效率降低
* @return
*/
public static LazySingleton getInstance2(){
if(instance==null){
// 线程不安全,可能会产生多个实例
synchronized(LazySingleton.class) {
if (instance == null){
instance = new LazySingleton();
}
}
}
return instance;
}
}
3)IoDH单例模式
class Singleton {
private Singleton() {
}
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return HolderClass.instance;
}
public static void main(String args[]) {
Singleton s1, s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();
System.out.println(s1==s2);
}
}
4优缺点及适用场景
主要优点:
1)单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。
2)由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
3)允许可变数目的实例。基于单例模式我们可以进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例,既节省系统资源,又解决了单例单例对象共享过多有损性能的问题。
主要缺点:
1)由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
2)单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
3)现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致共享的单例对象状态的丢失。
适用场景:
1)系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
2)客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。