这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
基于classloader机制,线程安全,没有锁,效率相对提高。但在类加载就初始化,浪费内存。
public class Singleton{ private static Singleton instance=new Singleton(); private Singleton(){}; public static Singleton getInstance(){ return instance; } }关于其名字由来:懒汉是在你真正用到的时候才去建这个单例对象。饿汉是不管你用不用的上,一开始就创建一个单例对象。
安全且在多线程情况下能保持高性能。
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的内存模型允许所谓的“无序写入”。具体情况可以看看这篇博文
这种方式能达到双重锁一样效果,对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
只有在要明确实现 lazy loading 效果时,才会使用这种方式。
它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
转载于:https://www.cnblogs.com/liyuxinBlog/p/8421696.html
