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();
        // com.doctor.design_pattern.singleton.EagerInitializedSingleton@2a139a55
        // com.doctor.design_pattern.singleton.EagerInitializedSingleton@2a139a55
        // 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());

        // com.doctor.design_pattern.singleton.StaticBlockSingleton@2a139a55
        // com.doctor.design_pattern.singleton.StaticBlockSingleton@2a139a55
        // 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();
}

时间: 2024-10-27 14:13:03

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

【设计模式】—— 单例模式Singleton

模式意图 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有公开的调用方法. 模式结构 Singleton 单例类,内部包含一个本身的对象.并且构造方法时私有的. 使用场景 当类只有一个实例,而且可以从一个固定的访问点访问它时. 代码结构 [饿汉模式]通过定义Static 变量,在类加载时,静态变量被初始化. 1 package com.xingoo.eagerSingleton; 2 class Singleton{ 3 private

解读设计模式----单例模式(Singleton Pattern)

单例模式可以保证一个类有且只有一个实例,并提供一个访问它的全局访问点.在程序设计中,有很多情况需要确保一个类只能有一个实例.从这句话可以看出,Singleton模式的核心:如何控制用户使用new对一个类的实例构造器的任意调用.如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?这应该是类设计者的责任,而不是使用者的责任. 一.单例模式意图 保证一个类有且只有一个实例,并提供一个访问它的全局访问点. 二.单例模式UML图(该图来至http://www.dofactory.com/) 三.示

.Net设计模式实例之单例模式( Singleton Pattern)

一.单例模式简介(Brief Introduction) 单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点.单例模式因为Singleton封装它的唯一实例,它就可以严格地控制客户怎样访问它以及何时访问它. 二.解决的问题(What To Solve) 当一个类只允许创建一个实例时,可以考虑使用单例模式. 三.单例模式分析(Analysis)1.单例模式结构 Singleton类,定义一个私有变量instance;私有构造方法Singleton(

C++和java设计模式之单例模式_C 语言

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点.其构造过程由自身完成,可以将构造方法定义为private型的,这样外界就只能通过定义的静态的函数Instance()构造实例,这个函数的目的就是返回一个类的实例,在此方法中去做是否有实例化的判断.客户端不再考虑是否需要去实例化的问题,把这些都交给了单例类自身.通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法,就是让类自身负责保存它的唯一实例.这个类可以保证没有其他实例可

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

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

java设计模式之单例模式学习_java

1 概述 单例模式有几个好处: (1)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销. (2)省去了new操作符,降低了系统内存的使用频率,减轻GC压力. (3)有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了. 2 详解 单例模式常用的写法有如下这么两种. 2.1 饿汉式 如果应用程序总是创建并使用单例模式,或者在创建和运行时压力不是很大的情况下,可以使用一个私有静态变量,提前把对象创建好. 复制代码 代码如下: package org.sc

.Net 单例模式(Singleton)

单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类   每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中.每台计算机可以有若干传真卡,但是只应该有一个软件负责管理传真卡,以避免出现两份传真作业同时传到传真卡中的情 况.每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用. 问题描述:         单例模式 Si

.Net 单例模式(Singleton)_实用技巧

每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中.每台计算机可以有若干传真卡,但是只应该有一个软件负责管理传真卡,以避免出现两份传真作业同时传到传真卡中的情况.每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用. 问题描述:         单例模式 Singleton Pattern 问题解决: (1)单例模式简介: Singleton模式要求一个类有且仅有一个实例,并且提供了一个

Java设计模式--单例模式

单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点. Singleton Pattern Ensure a class only has one instance, and provide a global point of access to it. 类图 模式的结构与使用 单例方法模式的结构中包括一种角色. + 单件类(Singleton):单件类只可以创建出一个实例. java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种: 懒汉式单例 饿汉式单例 登