java设计模式之单例模式(Singleton pattern)

java设计模式之单例模式(Singleton pattern)

单例模式的定义:

Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine. The singleton class must provide a global access
point to get the instance of the class.

限制一个类的实例在一个jvm实例中确保只有一个,而且必须提供一个全局访问点获得该单例。

为什么会出现单例模式:

  • 减少内存开支。由于单例在内存中相对于一个jvm实例内只有一个实例对象,不会重复的创建和jvm垃圾回收,对于内存减少了空间占用,也利于jvm垃圾回收处理。
  • 减少系统性能开销。当一个对象的产生依赖较多的资源时,比如读取配置或者依赖其他对象的时候,单例在jvm启动的时候预加载资源,然后可以永久驻留内存,当然也减少了jvm的垃圾回收线程的负担。
  • 当然还有很有的优势,现流行的spring框架就是默认支持单例模式(相对应spring容器)。

单例的实现方式:

实现单例模式的方式有很多不同手段,但以下几点我们会同时考虑:

  • 构造函数必须私有,不能让别人有权限随意实例化
  • 该单例一般在类中有一个私有静态变量
  • 该单例一般提供一个静态公共方法获得该单例(对于外界的该单例的全局访问点)

饿汉式(Eager initialization)

饿汉式单例实现方式是在类加载的时候初始化该单例。这种方式实现单例最简单,但也有个缺点就是即使我们应用中没有使用该类的单例,但类加载的时候也必须初始化。

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Created on 2016年7月31日 下午11:36:05
 *
 *         饿汉式 单例
 *         EagerInitialized Singleton
 */
public class EagerInitializedSingleton {
    private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();

    private EagerInitializedSingleton() {
    }

    public static EagerInitializedSingleton getInstance() {
        return instance;
    }

    public void doSomething() {
        System.out.println("test");
    }

    public static void main(String[] args) {
        System.out.println(EagerInitializedSingleton.getInstance());
        System.out.println(EagerInitializedSingleton.getInstance());
        EagerInitializedSingleton.getInstance().doSomething();
        // [email protected]139a55
        // [email protected]139a55
        // test

        System.out.println(EagerInitializedSingleton.getInstance() == EagerInitializedSingleton.getInstance());
        // true
    }

}

当单例没有涉及到过多的资源使用的时候,饿汉式单例比较适合。但很多场景下,单例的使用一般是为了使用一些资源比如文件系统、数据库连接等等,这中场景下,一般我们尽量使得该单例必须使用的时候,才会初始化,以避免资源的浪费使用。而且饿汉式单例也没提供异常的处理机制。

Static block initialization

静态块初始化单例和饿汉式单例相似,差别在于实例的初始化在静态块中,这中方式提供了异常处理。

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Created on 2016年8月1日 上午12:30:08
 */
public class StaticBlockSingleton {

    private static StaticBlockSingleton instance;

    public static StaticBlockSingleton getInstance() {
        return instance;
    }

    static {
        try {
            instance = new StaticBlockSingleton();
        } catch (Exception e) {
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
    }

    public static void main(String[] args) {
        System.out.println(StaticBlockSingleton.getInstance());
        System.out.println(StaticBlockSingleton.getInstance());

        System.out.println(StaticBlockSingleton.getInstance() == StaticBlockSingleton.getInstance());

        // [email protected]5
        // [email protected]5
        // true

    }

}

Lazy Initialization

懒初始化方法承担了单例的创建,并且是获取该单例的入口点。

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Created on 2016年8月1日 上午12:39:40
 */
public class LazyInitializedSingleton {

    private static LazyInitializedSingleton instance;

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

        return instance;
    }

    private LazyInitializedSingleton() {
    }

    public static void main(String[] args) {
        System.out.println(LazyInitializedSingleton.getInstance() == LazyInitializedSingleton.getInstance());// true
    }

}

上面几种单例的实现在单线程环境下可以很好的工作,但可能面临多线程安全问题。

Thread Safe Singleton

线程安全单例,简单的线程安全我们可以用

synchronized

实现。

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Created on 2016年8月1日 上午11:19:36
 *
 *         Thread Safe Singleton
 *
 */
public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;

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

    private ThreadSafeSingleton() {

    }

    public static void main(String[] args) {
        System.out.println(ThreadSafeSingleton.getInstance() == ThreadSafeSingleton.getInstance());
        // true
    }

}

上面的线程安全锁的粒度是比较大了,锁的粒度越大,并发性约不能,导致性能下降,我们可以用double checked locking
规则减少锁的粒度。

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Created on 2016年8月1日 上午11:37:25
 *
 *         double checked locking principle
 */
public class DoubleCheckedLockingThreadSafeSingleton {

    private static DoubleCheckedLockingThreadSafeSingleton instance;

    public static DoubleCheckedLockingThreadSafeSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckedLockingThreadSafeSingleton.class) {
                if (instance == null) {
                    instance = new DoubleCheckedLockingThreadSafeSingleton();
                }
            }
        }

        return instance;
    }

    private DoubleCheckedLockingThreadSafeSingleton() {

    }

    public static void main(String[] args) {

    }

}

Inner
static helper class
 Singleton

采用内部类来实现资源的懒加载:

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Inner static helper class Singleton
 *
 *
 *         Created on 2016年8月1日 上午11:54:05
 */
public class InnerStaticHelperClassSingleton {
    private InnerStaticHelperClassSingleton() {

    }

    public static InnerStaticHelperClassSingleton getInstance() {
        return SingletonHelper.instance;
    }

    private static class SingletonHelper {

        private static final InnerStaticHelperClassSingleton instance = new InnerStaticHelperClassSingleton();
    }

    public static void main(String[] args) {

    }

}

内部类拥有外部类的实例,当外部类被jvm加载的时候,内部类没有被加载,外部类的实例也就没有被实例化,当外部类真正的调用得到单例入口方法的时候,才会触发内部类的加载,同时外部类的单例也就初始化一次。

 这种方式的好处就是不用锁同步,就可以实现线程安全的单例。

枚举单例实现Enum Singleton

上面的单例实现可能由于反射导致不能保证一个类只有一个实例。下面的枚举实现方式克服了这个问题,但这种实现放手不能延迟加载。

package com.doctor.design_pattern.singleton;

/**
 * @author sdcuike
 *
 *         Enum Singleton
 *         枚举实现单例不能延迟加载资源,但保证了enum值只实例化一次。而且克服了反射带来的问题
 *
 *         Created on 2016年8月1日 下午12:24:06
 */
public enum EnumSingleton {
    instance;
    private EnumSingleton() {

    }

    public void doSomething() {
        System.out.println("test do ");
    }

    public static void main(String[] args) {
        EnumSingleton.instance.doSomething();
    }

}

序列化与单例

我们一般通过网络交互的时候都会用到序列化,序列化打破了单例的规则,反序列化我们得到了另一个实例(请自行验证)。为了保证序列化不影响单例规则,我们一般实现以下方法:

protected Object readResolve() {
    return getInstance();
}

具体请参考资料:http://docs.oracle.com/javase/1.5.0/docs/guide/serialization/spec/input.html

时间: 2025-01-03 15:09:58

java设计模式之单例模式(Singleton pattern)的相关文章

java设计模式之单例模式(Singleton)

Java设计模式之单例模式 单例模式是什么? 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式如何来设计呢? 保证一个类只能有一个实例,那么我们不能无限制的new 来创建,因为我们知道,new一次就是一个新的对象,那么构造器只能私有化private -- 构造器私有化 构造器私有化了,问题又出现了,构造器私有化了,那么我们怎么来创建唯一的对象呢?-- 提供一个公有的方法/提供一个公有的静态属性 再分析一下,公有方法, 实例方法还是类方法呢?--公有的类方法(获取类实例) 依据以上

设计模式之单例模式Singleton pattern

单例模式Singleton pattern 一种软件设计模式.在核心结构中只包含一个被称为单例的特殊类. 一个类只有一个对象实例,并且自行实例化向整个系统提供. 动机 一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务:一个系统只能有一个窗口管理器或文件系统:一个系统只能有一个计时工具或ID(序号)生成器.如在Windows中就只能打开一个任务管理器.如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源:如果这些窗口显示的内容不

二十四种设计模式:单例模式(Singleton Pattern)

单例模式(Singleton Pattern) 介绍保证一个类仅有一个实例,并提供一个访问它的全局访问点. 示例保证一个类仅有一个实例. Singleton using System; using System.Collections.Generic; using System.Text; namespace Pattern.Singleton { /// <summary> /// 泛型实现单例模式 /// </summary> /// <typeparam name=&q

(转)设计模式之——单例模式(Singleton)的常见应用场景

单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此有些设计大师并把把其称为设计模式之一. 这里又不具体讲如何实现单例模式和介绍其原理(因为这方便的已经有太多的好文章介绍了),如果对单例模式不了解的可以先看下:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html .当然也可以自己搜索.

(九)JAVA设计模式之单例模式

JAVA设计模式之单例模式 一.单例模式的介绍 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点.     全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量.最重要的是传统的全局对象并不能阻止一个类被实例化多次. 二.单例模式的特点 单例类只能有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例.

设计模式 - 单件模式(singleton pattern) 详解

单件模式(singleton pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/28595349 单件模式(singleton pattern) : 确保一个类只有一个实例, 并提供一个全局访问点. 单价模式包括3个部分: 私有构造器, 静态变量, 静态方法. 具体方法: 1. 标准的单例模式: /** * @time 2014.6.5 */ package singleton; /** * @author

java 设计模式之单例模式

--------2015-11-20 14:45:10 java设计模式之单例模式(Singleton): ---应用场合:只需要一个对象就可以了,例如一个朝代一个皇帝. ---作用:保证某个应用程序中某个实例有且只有一个.共同使用一个,节省资源. ---类型:饿汉模式,懒汉模式. 一.饿汉模式(类加载的时候就会实例化,线程安全) 1 package com.sun.singleton; 2 3 //饿汉模式 4 public class Singleton { 5 6 //将构造函数私有化,不

设计模式之单例模式——Singleton

                    设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有公开的调用方法.而且,别的类不能实例化它,所以构造方法要设置为私有的. 单例模式的要点 一是某个类只能有一个实例: 二是它必须自行创建这个实例: 三是它必须自行向整个系统提供这个实例. 例如: 有一个"单例对象",而"客户甲"."客户乙" 和&quo

Java设计模式之单例模式(七种写法)

Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleton instance; private Singleton (){}//私有化构造方法,防止类被实例化 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } retu