设计模式-Java-单例模式

一、应用场景

一般会在以下两种情况下采用单例模式:

  • 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。
  • 控制资源的情况下,方便资源之间的互相通信。

场景举例:

  • 为了方便线程池对池中的线程进行管理,一般线程池也会采用单例模式。
  •  操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
  • 外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件 
  • Windows的Task Manager(任务管理器)就是很典型的单例模式。
  • Windows的Recycle Bin(回收站)也是典型的单例应用。 
  • 网站的计数器,一般也是采用单例模式实现,否则难以同步。 
  •  Web应用的配置对象的读取,由于配置文件是共享的资源。
  • 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。

二、单例原则

  • 构造方法私有化。
  • 以静态方法或者枚举返回实例。
  • 实例化变量引用私有化。
  • 确保反序列转换时不会重新构建对象。

三、怎么写单例模式

(一)饿汉模式

饿汉模式在类被初始化时就已经在内存中创建了对象,以空间换时间,因此不存在线程安全问题。

package com.fuping.liuqu.demo.design.pattern.singleton;

/**
 * 单例模式,饿汉模式
 */
public class Singleton1 {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    private static final Singleton1 INSTANCE = new Singleton1();

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        return INSTANCE;
    }
}

(二)懒汉模式

懒汉模式在方法被调用后才创建对象,以时间换空间,在多线程环境下存在风险。

package com.fuping.liuqu.demo.design.pattern.singleton;

/**
 * 单例模式,懒汉模式
 */
public class Singleton2 {

    private String field;

    private static Singleton2 instance = null;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    private Singleton2() {
    }

    public static Singleton2 getInstance() {
        if (null == instance) {
            instance = new Singleton2();
        }
        return instance;
    }
}

(三)双重检入模式

必须给INSTANCE增加volatile描述,以解决指令重排序的问题。 

package com.fuping.liuqu.demo.design.pattern.singleton;

/**
 * 单例模式,双重检入模式
 */

public class Singleton3 {

    private String field;

    private volatile static Singleton3 INSTANCE = null;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    private Singleton3() {
    }

    public static Singleton3 getInstance() {
        if (null == INSTANCE) {
            synchronized (Singleton3.class) {
                if (null == INSTANCE) {
                    synchronized (Singleton3.class) {
                        INSTANCE = new Singleton3();
                    }
                }
            }
        }
        return INSTANCE;
    }
}

(四)静态内部类模式

静态内部类的优势在于第一次加载Singleton4类时不会去初始化INSTANCE,只有第一次调用getInstance,虚拟机加载SingletonHolder类并初始化INSTANCE,这样不仅能确保线程安全,也能保证 Singleton4 类的唯一性。

package com.fuping.liuqu.demo.design.pattern.singleton;

/**
 * 单例模式,静态内部类模式
 */
public class Singleton4 {

    private Singleton4() {
    }

    public Singleton4 getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final Singleton4 INSTANCE = new Singleton4();
    }
}

(五)单元素枚举模式

优势:

  • 可以避免反射攻击问题(构造方法私有化,并不能阻止类被反射)
  • 可以解决序列化问题
package com.fuping.liuqu.demo.design.pattern.singleton;

/**
 * 单例模式,枚举类模式
 */
public enum Singleton5 {

    INSTANCE;

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public Singleton5 getInstance() {
        return INSTANCE;
    }
}

猜你喜欢

转载自blog.csdn.net/u010313979/article/details/107108996