常见的设计模式(二)—单例模式

it2026-04-10  6

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

实现方式

 1.懒汉式:线程不安全,懒加载

public class Singleton { private static Singleton instance=null; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }

2.线程安全懒汉式:效率很低

public class Singleton{ private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }

3.饿汉式

基于classloader机制,线程安全,没有锁,效率相对提高。但在类加载就初始化,浪费内存。

public class Singleton{ private static Singleton instance=new Singleton(); private Singleton(){}; public static Singleton getInstance(){ return instance; } }

关于其名字由来:懒汉是在你真正用到的时候才去建这个单例对象。饿汉是不管你用不用的上,一开始就创建一个单例对象。

4.双重校验锁(DCL即double checked locking)

安全且在多线程情况下能保持高性能。

public class Singleton{ private volatile static Singleton singleton; private Singleton(){} public static Singleton getSingleton(){ if(singleton==null){ synchronized(Singleton.class){ if(singleton==null){ singleton=new Singleton(); } } } return singleton; } }

 1.为啥要判断两次空?

在同步块前判空是为了提高性能,如果没有判空,每个进入getInstance()都会得到一个静态内部锁,先判空能大大减少同步块的执行次数。第二次同步块里的判空是保证多线程的单例。

2.为啥要加volatile关键字

至于volatile关键字是避免指令重排,这就要归咎于JAVA的内存模型允许所谓的“无序写入”。具体情况可以看看这篇博文

5.静态内部类

public class Singleton{ private static class SingletonHolder{ private static final Singleton INSTANCE=new Singleton(); } private Singleton(){} public static final Singleton getInstance(){ return SingletonHolder.INSTANCE; } }

这种方式能达到双重锁一样效果,对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

只有在要明确实现 lazy loading 效果时,才会使用这种方式。

6.枚举

public enum Singleton { INSTANCE; public void whateverMethod() { } }

它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。

转载于:https://www.cnblogs.com/liyuxinBlog/p/8421696.html

最新回复(0)