单列设计模式--Java

什么是单列模式

保证一个类的实例是唯一的

单列模式的作用

  • 节省内存,不需要对一个类进行多次实例化,从而节省内存
  • 管理方便,比如Spring框架的IOC设计模式中冰山一角的思想一样,交给一个容器进行统一管理,减少类的滥用
  • 保证数据唯一性,在某些程序流程执行的过程中需要的唯一性,例如:简单的Java实现的网站访问统计

单列模式的几种实现方式

  1. 懒汉模式,这是线程不安全的,这是延迟加载的意思
public class TwelveT {  
   private static TwelveT instance;  
   
   // 禁止手动进行实例,应交由本类处理实例
   private TwelveT(){}  
 
   public static TwelveT getInstance() {  
	   if (instance == null) {  
	       instance = new TwelveT();  
	   }  
   		return instance;  
   }  
}
  1. 懒汉模式,线程安全的,由于是线程安全的,所以效率相对来说会有所减低
public class TwelveT {  
    private static TwelveT instance;  
    
    private TwelveT(){} 
    
    // 加上synchronized使得它是线程安全的
    public static synchronized TwelveT getInstance() {  
    if (instance == null) {  
        instance = new TwelveT();
    }  
    return instance;  
    }  
}
  1. DCL双锁检验模式,在这里提供一种解决可以通过反射破坏单列模式的一种方法,但并没有完全解决反射所带来的的问题,还有待解决
public class TwelveT {

    private static boolean flag = false;

    /**
     * 私有构造器,不允许直接new
     */
    private TwelveT() {
        synchronized (TwelveT.class) {

            if (flag == false) {
                flag = true;
            } else {
                throw new RuntimeException("不要试图通过反射破坏单例");
            }

        }
    }

    /**
     * 类初始化的时候,立即加载该对象
     * 1. 保证可见性(多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值)
     * 2. 不保证原子性(操作是可以中断,所以在并发中可能会出现一些问题)
     * 3. 禁止指令重排(禁止编译器和CPU可能的对执行指令重新排序带来的问题)
     */
    private volatile static TwelveT instance;

    /**
     * 提供获取对象的方法,没有synchronized,效率高
     * 使用synchronized代码块进行双重判断,效率比直接synchronized性能高
     *
     * @return
     */
    public static TwelveT getInstance() {
        if (instance == null) {
            synchronized (TwelveT.class) {
                if (instance == null) {
                    instance = new TwelveT();
                }
            }
        }
        return instance;
    }
}

// 以下代码示例一下反射破坏单列,明显执行失败的
class SingletonTest{
    public static void main(String[] args) throws Exception {
        // 正常获取实例
        TwelveT instance = TwelveT.getInstance();

        Constructor<TwelveT> declaredConstructor = TwelveT.class.getDeclaredConstructor();
        // 允许通过反射访问受保护的资源
        declaredConstructor.setAccessible(true);
        // 获取实例,直接抛出错误
        TwelveT instance02 = declaredConstructor.newInstance();

        System.out.println(instance == instance02);

    }
}
  1. 饿汉式,线程不安全的方式,在Java当中这种设计模式在程序启动的时候就会被立即加载,也就是没有使用我们的延迟加载,一但这种设计写多了,程序的启动将会非常缓慢,慎用
public class TwelveT {  
    private static TwelveT instance = new TwelveT();  
    
    private TwelveT(){}
    
    public static TwelveT getInstance() { 
    	return instance; 
    }  
}
  1. 枚举
public enum TwelveT {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}
  1. 登记式(内部类实现的懒汉式),内部类只有在外部类被调用才加载,而且不用加锁,此模式有懒汉式以及饿汉的优点,屏蔽了他们的一些缺点,可以说是最好的单例模式。
public class TwelveT {
    private static class TwelveTHolder {
        private static final TwelveT INSTANCE = new TwelveT();
    }

    private TwelveT() {
    }

    public static final TwelveT getInstance() {
        return TwelveTHolder.INSTANCE;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值