原文链接:http://www.ibm.com/developerworks/cn/java/j-lo-Singleton/index.html
http://blog.csdn.net/jason0539/article/details/23297037
单例模式
考虑这样一个应用,读取配置文件的内容。很多应用项目,都有与应用相关的配置文件,这些配置文件很多是由项目开发人员自定义的,在里面定义一些应用重要的参数数据。当然,在实际的项目中,这种配置文件多数采用 xml 格式,也有采用 properties 格式的,我们这里假设创建了一个名为 AppConfig 的类,它专门用来读取配置文件内的信息。客户端通过 new 一个 AppConfig 的实例来得到一个操作配置文件内容的对象。如果在系统运行中,有很多地方都需要使用配置文件的内容,也就是说很多地方都需要创建 AppConfig 对象的实例。换句话说,在系统运行期间,系统中会存在很多个 AppConfig 的实例对象,这里读者有没有发现有什么问题存在?当然有问题了,试想一下,每一个 AppConfig 实例对象里面都封装着配置文件的内容,系统中有多个 AppConfig 实例对象,也就是说系统中会同时存在多份配置文件的内容,这样会严重浪费内存资源。如果配置文件内容越多,对于系统资源的浪费程度就越大。事实上,对于 AppConfig 这样的类,在运行期间只需要一个实例对象就足够了。
从专业化来说,单例模式是一种对象创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。Java 里面实现的单例是一个虚拟机的范围,因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的 ClassLoad 装载实现单例类的时候就会创建一个类的实例。在 Java 语言中,这样的行为能带来两大好处:
-
对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
-
由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
因此对于系统的关键组件和被频繁使用的对象,使用单例模式可以有效地改善系统的性能。单例模式的核心在于通过一个接口返回唯一的对象实例。首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类的实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
一、懒汉式单例
- //懒汉式单例类.在第一次调用的时候实例化自己
- public class Singleton {
- private Singleton() {}
- private static Singleton single=null;
- //静态工厂方法
- public static Singleton getInstance() {
- if (single == null) {
- single = new Singleton();
- }
- return single;
- }
- }
(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)
但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全,如果你第一次接触单例模式,对线程安全不是很了解,可以先跳过下面这三小条,去看饿汉式单例,等看完后面再回头考虑线程安全的问题:
1、在getInstance方法上加同步
- public static synchronized Singleton getInstance() {
- if (single == null) {
- single = new Singleton();
- }
- return single;
- }
2、双重检查锁定
- public static Singleton getInstance() {
- if (singleton == null) {
- synchronized (Singleton.class) {
- if (singleton == null) {
- singleton = new Singleton();
- }
- }
- }
- return singleton;
- }
3、静态内部类
- public class Singleton {
- private static class LazyHolder {
- private static final Singleton INSTANCE = new Singleton();
- }
- private Singleton (){}
- public static final Singleton getInstance() {
- return LazyHolder.INSTANCE;
- }
- }
这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。
二、饿汉式单例
- //饿汉式单例类.在类初始化时,已经自行实例化
- public class Singleton1 {
- private Singleton1() {}
- private static final Singleton1 single = new Singleton1();
- //静态工厂方法
- public static Singleton1 getInstance() {
- return single;
- }
- }
总结:
单例模式是用来实现在整个程序中只有一个实例的设计模式方法。本文通过从最基础的单例模式开始讲解,逐渐进入到延迟加载、锁机制、内部、静态类等单例模式实现方法,让读者可以学习单例模式的具体应用。设计模式的核心理念是活学活用,所以不会有什么规则是固定不变的规则,需要读者在实际应用过程中不断尝试、不断创新,力求代码间接明了、易于扩展。