保证在内存中只有一个实例
- 构造方法私有,只能通过getInstance()获取实例
- 静态对象,同一个类共享
饿汉式
类加载到内存后,实例话一个单例,jvm保证线程安全
- 简单实用
不管是否使用,都在类加载时完成了实例化 ```java public class Singleton01 {
private static final Singleton01 instance = new Singleton01();
private Singleton01() { }
public static Singleton01 getInstance(){
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;
}
