保证在内存中只有一个实例

  1. 构造方法私有,只能通过getInstance()获取实例
  2. 静态对象,同一个类共享

饿汉式

类加载到内存后,实例话一个单例,jvm保证线程安全

  • 简单实用
  • 不管是否使用,都在类加载时完成了实例化 ```java public class Singleton01 {

    private static final Singleton01 instance = new Singleton01();

    private Singleton01() { }

    public static Singleton01 getInstance(){

    1. return instance;

    } }


---

<a name="1d1f0987a4be8585d4e56c8805227e95"></a>
## 懒汉式
懒加载<br />双重检测法,加锁保证线程安全<br />加上volatile防止JIT的时候指令重排<br />new一个对象分为3步:

1. 分配内存空间
1. 属性赋值
1. 对象指针指向内存地址

其中第2步第3步可能出现指令重排,导致不加volatile的对象get出来是没有经过属性赋值的半成品。
```java
public class Singleton02 {

    private static volatile Singleton02 instance;//JIT

    private Singleton02() {
    }

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

静态内部类法
只加载外部类时不会加载静态内部类,jvm保证线程安全,也实现了懒加载

public class Singleton03 {

    private static class Singleton03Holder{
        private final static Singleton03 instance = new Singleton03();
    }    

    private Singleton03() {
    }

    public static Singleton03 getInstance(){
        return Singleton03Holder.instance;
    }
}

反射破坏单例模式

public void test(){
        try{
            Class<?> clazz = Singleton03.class;
            Constructor c = clazz.getDeclaredConstructor(null);
            c.setAccessible(true);
            Object o1 = c.newInstance();
            Object o2 = c.newInstance();
            System.out.println(o1 == o2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

枚举法
枚举类没有构造方法,就算拿到Class也无法反射,防止反序列化

public enum Singleton04 {

    INSTANCE;
}