把稳:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他工具供应这一实例。

意图:担保一个类仅有一个实例,并供应一个访问它的全局访问点。

单个建筑设计道理 工艺流程

紧张办理:一个全局利用的类频繁地创建与销毁。

何时利用:当您想掌握实例数目,节省系统资源的时候。

如何办理:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:布局函数是私有的。

下面是单例模式实现的几种办法。

一:静态内部类实现单例模式

事理:通过一个静态内部类定义一个静态变量来持有当前类实例,在类加载时就创建好,在利用时获取。
缺陷:无法做到延迟创建工具,在类加载时进行创建会导致初始化韶光变长。

public class Singleton {

private static class xx {

private static Singleton singleton = new Singleton();

}

private Singleton(){}

public static Singleton getInatance(){

return xx.singleton;

}

}

二:饿汉模式

事理:创建好一个静态变量,每次利用时直接返回。
缺陷:无法做到延迟创建工具,在类加载时进行创建会导致初始化韶光变长。

public class Singleton {

private static Singleton instance = new Singleton();

private Singleton() {

}

public static Singleton getInstance() {

return instance;

}

三:

事理:延迟创建,在第一次用时才创建,之后每次用到就返回创建好的。
缺陷:由于synchronized的存在,多线程时效率很低。

public class Singleton {

private static volatile Singleton instance;

private Singleton() { }

public static synchronized Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

四:双重校验锁

事理:在getSingleton()方法中,进行两次null检讨。
这样可以极大提升并发度,进而提升性能。

public class Singleton {

private static volatile Singleton uniqueInstance = null;//利用valatile,使该变量能被所有线程可见

private Singleton(){}

public static Singleton getSingleton(){

if(uniqueInstance == null){

synchronized (Singleton.class){//初始化时,加锁创建

if(uniqueInstance == null){//为避免在加锁过程中被其他线程创建了,再作一次非空校验

uniqueInstance = new Singleton();

}

}

}

return uniqueInstance;

}

五:上述4种办法实现单例模式的缺陷

1、反序列化工具时会毁坏单例,反序列化工具时不会调用getXX()方法,于是绕过了确保单例的逻辑,直接天生了一个新的工具,毁坏了单例。
办理办法是:重写类的反序列化方法,在反序列化方法中返回单例而不是创建一个新的工具。

public class Singleton implements Serializable {

public static Singleton instance = new Singleton();

private Singleton() {

}

//反序列时直接返回当前Instance

// 如果该工具被序列化,可以担保工具在序列化前后保持同等。

private Object readResolve() {

return Instance;

}

}

2、在代码中通过反射机制,直接调用类的私有布局函数创建新的工具,会毁坏单例,办理办法是:掩护一个volatile的标志变量在第一次创建实例时置为false;重写布局函数,根据标志变量决定是否许可创建。

private static volatile boolean flag = true;

private Singleton(){

if(flag){

flag = false; //第一次创建时,改变标志

}else{

throw new RuntimeException("The instance already exists !
");

}

六:列举模式实现单例——将单例掩护在列举类中作为唯一的实例。

事理:定义列举类型,里面只掩护一个实例,以此担保单例。
每次取用时都从列举中取,而不会取到其他实例。

public enum SingletonEnum {

INSTANCE;

private String name;

public String getName(){

return name;

}

public void setName(String name){

this.name = name;

}

优点:1)利用SingletonEnum.INSTANCE进行访问,无需再定义getInstance方法和调用该方法。
2)JVM对列举实例的唯一性,避免了上面提到的反序列化和反射机制破环单例的情形涌现:每一个列举类型和定义的列举变量在JVM中都是唯一的。

缘故原由:列举类型在序列化时仅仅是将列举工具的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找列举工具。
同时,编译器禁止重写列举类型的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。