Java单例模式

单例模式

  单例模式核心是保证一个类只有一个实例,并且提供一个访问实例的全局访问点。

使用场景

  需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)

  • Spring中bean对象的模式实现方式
  • servlet中每个servlet的实例
  • spring mvc和struts1框架中,控制器对象是单例模式
  • 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加
  • 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统
  • 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源
  • Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
  • windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  • 网站的计数器,一般也是采用单例模式实现,否则难以同步。
  • 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  • Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。

单例模式优点

  单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能

单例模式缺点

  扩展困难,滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

实现方式

懒汉模式(线程不安全)

是否 Lazy 初始化:是
是否多线程安全:否
描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

public class singleton {
        private static singleton instance;
        private singleton (){}
        public static singleton getInstance() {
            if (instance == null) {
                instance = new singleton();
            }
            return instance;
        }
    }

懒汉模式(线程安全)

是否 Lazy 初始化:是
是否多线程安全:是
这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

饿汉模式

是否 Lazy 初始化:否
是否多线程安全:是
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。


public class Singleton {  
    private static Singleton instance = new Singleton();
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

饿汉模式(静态代码块)

1.在类加载的时候便完成了实例化.
2.在初始化的时候可以进行一些属性的初始化.

public class singleton2 {
    private static final singleton2 SINGLETON_2;
    int anInt;
    static {
        SINGLETON_2 = new singleton2(1);
    }
    private singleton2(int anInt) {
        this.anInt = anInt;
    }
    public static singleton2 getInstance() {
        return SINGLETON_2;
    }
}

双检锁/双重校验锁

JDK 版本:JDK1.5 起
是否 Lazy 初始化:是
是否多线程安全:是
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
            if (singleton == null) {  
                singleton = new Singleton();  
            }  
        }  
    }  
    return singleton;  
    }  
}

静态内部类

是否 Lazy 初始化:是
是否多线程安全:是

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}

本文作者:Eureka98

本文链接:https://www.cnblogs.com/todayiswendy/p/16711925.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Eureka98  阅读(52)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起