Singleton_单例模式
应用场景:在程序只需要有一个实例存在的情况下,你可以在编写代码的时候只创建一个实例,但如何保证其他人不能通过构造器new一个新的实例呢?目前我了解到的可行方案有:
- 饿汉式
- 懒汉式
- 双重检测锁式
- 静态内部类式
- 单元素枚举类式
大多数情况下使用饿汉式即可,如果实例必须懒加载推荐使用静态内部类式,当然最完美的方式还是单元素枚举类式,但使用enum来创建类多少有点不习惯...
1. 饿汉式
饿汉式,构造器声明为私有,只能类内部访问,所以外界无法通过构造器将对象实例化。当类加载到内存后,在给常量初始化时就实例化一个对象,JVM会帮我们保证线程安全,只需要留一个公开的访问器即可。这个实现方式简单实用,唯一缺点是不管用到与否,类装载时就完成实例化。
public class Demo{
private final static Demo INSTANCE = new Demo();
private Demo(){};
public static Demo getInstance(){ return DemoHolder.INSTANCE; }
}
2. 懒汉式
懒汉式lazy looding,为了追求完美,实现单例的懒加载,将单例声明为变量,在调用时才进行初始化让类实例化,虽然达到了按需初始化的目的,但却带来了线程不安全的问题,于是我们给方法加锁,这虽然解决了线程安全问题,但执行效率不高。
public class Demo{
private static Demo INSTANCE;
public static synchronized Demo getInstance(){
if(INSTANCE == null){ INSTANCE = new Demo(); }
return INSTANCE;
}
}
3. 双重检测锁式
为了提高效率使用了代码块锁,结果再次出现线程安全问题,需要使用双重检测来解决使用代码块锁出现的线程安全问题,最后需求是满足了但太麻烦了,不推荐使用。
public class Demo{
private static Demo INSTANCE;
private Demo() {};
public static Demo getInstance(){
if(INSTANCE == null){
synchronized (Demo.class){
if(INSTANCE == null){ INSTANCE = new Demo(); }
}
}
return INSTANCE;
}
}
4. 静态内部类式
我们在使用饿汉式时,唯一的缺点就是不能懒加载,而如果配合静态内部类使用,可以解决懒加载的问题。我们可以利用加载外部类时不会加载静态内部类这个特性来实现常量的懒加载。推荐使用。
public class Demo{
private Demo(){};
private static class DemoHolder{
private final static Demo INSTANCE = new Demo();
}
public static Demo getInstance(){ return DemoHolder.INSTANCE; }
}
5. 枚举式
单元素的枚举类型已经成为实现Singleton的最佳方法。
---《Effective Java》Joshua Bloch
优点:使用简洁,实现懒加载,线程同步,效率高,还可以防止反序列化。
缺点:完美!
public enum Demo{
INSTANCE;
}
总结:单例模式的关键就在对外隐藏构造器上。枚举类由于没有构造器完美决绝问题。饿汉式和懒汉式都是通过将构造器声明为私有来让外界无法使用构造器。双重检测锁式和静态内部类式其实就是懒汉式和饿汉式的基础上进行升级。
本文来自博客园,作者:独游空想家,转载请注明原文链接:https://www.cnblogs.com/linzhikai/p/16501471.html