一、单例模式的优点和缺点
单例模式的优点:
- 单例模式可以保证内存里只有一个实例,减少了内存的开销。
- 可以避免对资源的多重占用。
- 单例模式设置全局访问点,可以优化和共享资源的访问。
单例模式的缺点:
- 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
- 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
- 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
二、单例模式的实现
1.懒汉式
优点:单例只有在使用时才被实例化,一定程度上节约了资源
缺点:非线程安全。
public class LazySingleton {
private static volatile LazySingleton instance = null;
private LazySingleton(){
}
public static synchronized LazySingleton getInstance(){
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
2.饿汉式
说明:声明静态时已经初始化,在获取对象之前就初始化
优点:获取对象的速度快,线程安全(因为虚拟机保证只会装载一次,在装载类的时候不会发生并发)
缺点:耗内存(若类中有静态方法,在调用静态方法的时候类就会被加载,类加载的时候就完成了单例的初始化,拖慢速度)
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return instance;
}
}
3.双重检查锁(推荐)
优点:既能保证线程安全,且单例对象初始化后调用getInstance不进行同步锁,资源利用率高
缺点:第一次加载稍慢,由于Java内存模型一些原因偶尔会失败,在高并发环境下也有一定的缺陷,但概率很小。
public class SingletonDoubleKey {
private volatile static SingletonDoubleKey instance = null; //volatitle是为了避免双重锁定失效
private SingletonDoubleKey(){}
//synchronized 如果加在方法上,每次访问都进行同步锁,浪费性能。
public static SingletonDoubleKey getInstance(){ //
if (instance == null){ //避免不必要的同步
synchronized (SingletonDoubleKey.class){ //类锁,synchronized(this)是对象锁。
if(instance == null){ //在null的情况下创建实例
instance = new SingletonDoubleKey();
}
}
}
return instance;
}
}