Singleton单例模式

保证一个类只有一个实例,并且提供一个访问该示例的全局访问点。

常见场景:

  • windows的Task Manager(任务管理器)就是很经典的单例模式
  • windows的Recycle Bin(回收站)
  • 项目中,读取配置的文件类,一般也只有一个,没有不要每次使用配置文件数据,每次new一个对象去读取
  • 网站的计数器,一般也采用单例模式,否则难以同步
  • 应用程序日志应用,一般都采用单例模式,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容也不好追加。

优点:

  • 单例模式只生成一个实例。减少了系统性能的开销吗,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久存在内存的方式来解决;
  • 单例模式可以在系统设置全局访问的访问点,优化工系哦啊资源访问。例如可以设计一个单例来负责所有的数据表的迎合处理。

常见的五种单例模式实现方式

  • 饿汉式(线程安全,调用效率高,不能延时加载)
public class SingletonDemo1 {
    //类初始化时立即加载这个对象(没有延时加载的优势),加载类时,是线程安全的.
    private static SingletonDemo1 instance = new SingletonDemo1();
    private SingletonDemo1() {}//私有构造器
    //方法没有同步synchronized,调用效率高
    public static SingletonDemo1 getInstance() {
        return instance;
    }
}
  • 懒汉式(线程安全,调用效率不高,可以延时加载)
public class SingletonDemo1 {
    //类初始化时,不加载这个对象(延时加载,真正用时候再创建)
    private static SingletonDemo1 instance;
    private SingletonDemo1() {
        if (instance != null) {
            throw new RuntimeException();
        }
    } //私有构造器
    //资源利用率高了,但是每次调用方法度要同步,并发效率较低
    public static synchronized SingletonDemo1 getInstance() {
        return instance == null ? new SingletonDemo1() : instance;
    }
}

   DCL

  • 双重检测锁式:

将同步内容下放到if内部,提高了执行的效率不必每次获取对象。

《Java并发编程实战》如果声明为volatile类型就能启用DCL,volatile变量读取操作对性能通常只是略高于非volatile变量读取操作的性能。然而,DCL的这种使用方法已经被广泛的废弃了,因而它不是一种高效的优化措施。”

public class SingletonDemo1 {
    //类初始化时,不加载这个对象(延时加载,真正用时候再创建)
    private static volatile SingletonDemo1 instance;
    private SingletonDemo1() {} //私有构造器
    //资源利用率高了,但是每次调用方法度要同步,并发效率较低
    public static SingletonDemo1 getInstance() {
        if(instance == null){
            synchronized(SingletonDemo1.class ){
                if(instance == null)
                    instance = new SingletonDemo1(); 
            }
        } 
        return instance;
    }
}
  • 静态内部类式(线程安全,调用效率较高,可以延时加载)
public class SingletonDemo1 {
    private static class SingletonClassInstance {
        private static SingletonDemo1 instance = new SingletonDemo1();
    }
    //私有构造器
    private SingletonDemo1() {}
    public static synchronized SingletonDemo1 getInstance() {
        return SingletonClassInstance.instance;
    }
}

外部类没有static属性,则不会像饿汉式立即加载。

只有真正调用getInstance()才会加载静态内部类。加载是线程安全的,instance是static final类型,保证了内存中只有这样一个实例,而且只能赋值一次。从而保证了线程的安全。

兼备了并发高效调用和延迟加载的优势

  • 枚举单例(线程安全,调用效率高,避免根据反射和反序列化的漏洞,不能延时加载)
public enum Singleton {
    INSTANCE;//这个枚举元素本身就是单例模式
    public void singletonOperation() {
        //todo
    }
}

如何选用?

       创建单例对象 占用 资源少,不需要延时加载:枚举 > 饿汉

       创建单例对象 占用 资源大,需要延时加载:静态内部类式 > 懒汉式

问题:

       反射可以破解单例(不含枚举)实现方式:可以在构造方法中手动抛出异常控制

       反序列化可以破解单例(不含枚举)实现方式:通过定义readResolve()防止获得不同对象,定义返回指定对象。

 

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读