单例模式的主要优点如下: (1) 单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严 格控制客户怎样以及何时访问它。 (2) 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销 毁的对象单例模式无疑可以提高系统的性能。 (3) 允许可变数目的实例。基于单例模式我们可以进行扩展,使用与单例控制相似的方法来获 得指定个数的对象实例,既节省系统资源,又解决了单例单例对象共享过多有损性能的问 题。 2.主要缺点 单例模式的主要缺点如下: (1) 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。 (2) 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角 色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的 本身的功能融合到一起。 (3) 现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如 果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次 利用时又将重新实例化,这将导致共享的单例对象状态的丢失。 3.适用场景 在以下情况下可以考虑使用单例模式: (1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者 需要考虑资源消耗太大而只允许创建一个对象。 (2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途 径访问该实例。 思考 如何对单例模式进行改造,使得系统中某个类的对象可以存在有限多个,例如两例或三例? 【注:改造之后的类可称之为多例类。】
饿汉模式:
public class Esingleton {
private Esingleton() {
}
private static Esingleton ins = new Esingleton();
public static Esingleton Instance() {
return ins;
}
public static void main(String[] args) {
Esingleton esingleton = Esingleton.Instance();
Esingleton esingleton1 = Esingleton.Instance();
System.out.println(esingleton == esingleton1);
}
}
懒汉模式:
public class Lsingleton {
private Lsingleton() {
}
private static Lsingleton instance = null;
public static Lsingleton Instance() {
if (instance == null)
instance = new Lsingleton();
return instance;
}
public static void main(String[] args) {
Lsingleton lsingleton = Lsingleton.Instance();
Lsingleton lsingleton1 = Lsingleton.Instance();
System.out.println(lsingleton == lsingleton1);
}
}
IoDH( Initialization Demand Holder ) 模式:
public class Singleton {
private Singleton() {
}
private static class InnerClass {
private final static Singleton instance = new Singleton();
}
public static Singleton Instance() {
return InnerClass.instance;
}
public static void main(String[] args) {
Singleton singleton = Singleton.Instance();
Singleton singleton1 = Singleton.Instance();
System.out.println(singleton == singleton1);
}
}
多线程下改造懒汉模式:
public class Lsingleton {
private Lsingleton() {
}
/**
* 变量对所有线程共享
*/
private volatile static Lsingleton instance = null;
public static Lsingleton Instance() {
//双重锁校验
if (instance == null)
synchronized (Lsingleton.class) {
if (instance == null)
instance = new Lsingleton();
}
return instance;
}
public static void main(String[] args) {
Lsingleton lsingleton = Lsingleton.Instance();
Lsingleton lsingleton1 = Lsingleton.Instance();
System.out.println(lsingleton == lsingleton1);
Queue<Test> queue = new ArrayBlockingQueue<Test>(100);
List<Thread> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(new Thread(() -> {
queue.add(Test.getInstance());
}));
}
for (Thread thread : list) {
thread.start();
}
while (queue.size() != 100);
System.out.println(""+JSON.toJSONString(queue));
}
}