1、单例模式
1.1 简介
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类 只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
1.2 创建单例模式的八种方法
方法一:恶汉式1-静态变量(No Lazy)
public class Singleton1 {
//1.构造器私有化
private Singleton1() {}
//2.创建静态对象实例
private static final Singleton1 INSTANCE = new Singleton1();
//3.公共方法返回对象实例
public static Singleton1 getInstance() {
return INSTANCE;
}
}
优:装载类的时候完成实例化,避免线程安全问题
缺:非懒加载,会造成内存浪费
结论:可用,但会造成内存浪费
方法二:恶汉式2-静态代码块(No Lazy)
public class Singleton2 {
//1.构造器私有化
private Singleton2() {}
//2.创建静态变量
private static Singleton2 INSTANCE;
//3.使用静态代码块创建实例
static {
INSTANCE = new Singleton2();
}
//4.公共方法返回对象实例
public static Singleton2 getInstance() {
return INSTANCE;
}
}
优缺点与上面的情况类似
方法三:懒汉式1-静态方法(线程不安全)
public class Singleton3 {
//1.构造器私有化
private Singleton3() {}
//2.创建静态变量
private static Singleton3 singleton3;
//4.公共方法返回对象实例
public static Singleton3 getInstance() {
if (singleton3 == null) {
singleton3 = new Singleton3();
}
return singleton3;
}
}
优:懒加载
缺:线程不安全
总结:不要使用
方法四:懒汉式2-同步方法(线程安全)
public class Singleton4 {
//1.构造器私有化
private Singleton4() {}
//2.创建静态变量
private static Singleton4 singleton4;
//3.公共方法返回对象实例
public static synchronized Singleton4 getInstance() {
if (singleton4 == null) {
singleton4 = new Singleton4();
}
return singleton4;
}
}
优:线程安全
缺:效率低, 每个线程在想获得类的实例时候,执行getInstance()方法都要进行 同步。
方法五:懒汉式3-同步代码块(不可实现单例)
public class Singleton5 {
//1.构造器私有化
private Singleton5() {}
//2.创建静态变量
private static Singleton5 singleton5;
//3.公共方法返回对象实例
public static Singleton5 getInstance() {
if (singleton5 == null) {
synchronized (Singleton5.class) {
singleton5 = new Singleton5();
}
}
return singleton5;
}
}
本意是对方法四的改进,但是又出现了线程安全问题,不可以使用
方法六:双重检查-同步代码块
public class Singleton6 {
//1.构造器私有化
private Singleton6() {}
//2.创建静态变量
//volatile关键字的作用是保证了不同线程之间对共享变量操作时的可见性,
// 也就是说当一个线程修改volitail修饰的变量,另外一个线程会立即看到最新的值,更利于线程安全
private static volatile Singleton6 singleton6;
//3.公共方法返回对象实例
public static Singleton6 getInstance() {
if (singleton6 == null) {
synchronized (Singleton6.class) {
if (singleton6 == null) {
singleton6 = new Singleton6();
}
}
}
return singleton6;
}
}
双重检查,对于只有最开始同时进入外层if语句的线程需要同步等待,后续的线程不会进入外层if语句,直接return
方法七:静态内部类
public class Singleton7 {
//1.构造器私有化
private Singleton7() {}
//2.创建静态内部类
private static class SingletonInstance {
private static final Singleton7 INSTANCE = new Singleton7();
}
//3.公共方法返回对象实例
public static Singleton7 getInstance() {
return SingletonInstance.INSTANCE;
}
}
利用类装载的机制来保证实例化时只有一个对象,只有调用getInstance()方法,才会加载SingletonInstance类,从而实现懒加载,由于内部类的属性静态INSTANCE只会由装载一次,从而避免了线程不安全(与方法一类似,但是延迟了静态变量的加载)
方法八:枚举类
public enum Singleton8 {
INSTANCE;
public void method() {
// to do...
}
}
超级简单,不容易出错
而且枚举类实现了可序列化接口,也能防止反序列化创建新的对象
枚举的属性自带public static final修饰,是static的属性
1.3 总结
单例模式 懒加载 线程安全 反序列化 推荐使用
单例模式 | 懒加载 | 线程安全 | 反序列化 | 推荐使用(等级) |
---|---|---|---|---|
饿汉式1 | ❌ | ✅ | ❌ | ✅ |
饿汉式2 | ❌ | ✅ | ❌ | ✅ |
懒汉式1 | ✅ | ❌ | ❌ | ❌ |
懒汉式2 | ✅ | ✅ | ❌ | ✅ |
懒汉式3 | ✅ | ❌ | ❌ | ❌ |
双重检查 | ✅ | ✅ | ❌ | ✅✅ |
静态内部类 | ✅ | ✅ | ❌ | ✅✅ |
枚举类 | ❌ | ✅ | ✅ | ✅✅✅ |