`

Java之设计模式之Singleton

阅读更多
Java之设计模式之Singleton

Java Singleton 单例设计模式属于四大设计模式之生产设计模式的一种。
该设计模式看似简单,但是涉及到许多注意点。

一、Java Singleton 简介

Java Singleton 单例设计只允许在JVM中产生类的一个实例对象。
因此这样的类不能提供对外的构造方法产生实例,而是提供一个 public 方法,
返回(指向)某个实例的引用。

Java Singleton 单例设计常用于:
1、Logging(日志)
2、Driver(驱动)
3、Caching(缓存)
4、Thread Pool(线程池)
5、Abstract Factory(抽象工厂)
6、Builder(构建器)
7、Prototype(原型设计)
8、Facade Design Pattern

在 core java 中也有出现单例模式的设计:
java.lang.Runtime
java.awt.Desktop


二、实现 Java Singleton

实现单例需要符合下列三点:
1、private 的构造方法。阻止除本类外的其他类对该类进行实例的构建。
2、private , static 的属性。这就是那个单例。
3、public static 的方法,用于对外返回单例。


单例的实现有以下几种方式:

按初始化分:
1、Eager initializtion (急初始化)
2、Static block initializtion (静态块初始化)
3、Lazy initializtion (懒初始化)

按线程安全分:
4、Thread Safe Singleton(线程安全式单例)
5、Bill Push Singleton(Bill Push 单例)


下面将逐一讲解:

1、Eager initializtion (急初始化)

急初始化模式下,单例在 Class 被 JVM 加载时即被创建。

优点:
    -容易实现。

缺点:
    -该类未被使用到时也被初始化。
    -不能进行异常处理。

点评:
如果使用较少的资源,可以使用此方法。
多数情形下,如 File System,Database Connection,应避免使用此方法。

代码:
public class EagerInitializedSingleton {
    
    private static final EagerInitializedSingleton instance 
                             = new EagerInitializedSingleton();
    
    //私有构造方法,避免其它类在该类外部构造此类的实例。
    private EagerInitializedSingleton(){}

    public static EagerInitializedSingleton getInstance(){
        return instance;
    }
}



2、Static block initializtion (静态块初始化)

静态块初始化方法跟急初始化差不多,只是可以在静态块中处理异常。
public class StaticBlockSingleton {

    private static StaticBlockSingleton instance;
    
    private StaticBlockSingleton(){}
    
    //static block initialization for exception handling
    static{
        try{
            instance = new StaticBlockSingleton();
        }catch(Exception e){
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
    }
    
    public static StaticBlockSingleton getInstance(){
        return instance;
    }
}



3、Lazy initializtion (懒初始化)

懒初始化单例设计模式,是在对外的 public 方法中生成实例对象的。
只需加一个是否为空的判断即可。

public class LazyInitializedSingleton {

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


上面3种单例设计方式,在单线程的环境下可以正常工作。
但是,在多线程的环境下不行:当多个线程同时运行在 if 块内,
可能会产生多个实例对象。

下面讲述多线程环境下的单例模式。

4、Thread Safe Singleton(线程安全式单例)

最简单的实现是给对外公开的 public 的方法增加 synchronized 修饰符。

说明:关于 synchronized修饰符

这样一次只能有一个线程可以访问该方法。
public class ThreadSafeSingleton {

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

上面的方法在功能实现角度上是没有任何问题的。但是有一缺陷:效率比较低。
其实,只需对实例第一次产生时进行 synchroinized 即可。

改进:
public class ThreadSafeDoubleCheckingSingleton {

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


5、Bill Push Singleton(Bill Push 单例)

在 Java 1.5 之前,java 内存模型有很多问题。
尤其是线程很多的情况下,上面的实现方式会莫名其妙的失效。

于是乎,Bill Push 提出了单例模式的另一种实现方式:借助内部类。
public class BillPughSingleton {

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


内部类何时被初始化?
当类被 JVM 装载时,内部类不会被装载,直到 getInstance() 方法被调用。


这是被最广泛使用的线程安全的单例模式。
因为它不需要任何的 synchronized 修饰符。


三、Java Singleton 之继续讨论

1、Using Reflection to destroy Signleton Pattern

使用反射来破坏单例设计模式:
当使用反射机制生成类的实例时,上述单例设计方法便失效了。
public class ReflectionSingletonTest {

    public static void main(String[] args) throws Exception{
        EagerInitializedSingleton instanceOne = 
                                   EagerInitializedSingleton.getInstance();        
        EagerInitializedSingleton instanceTwo = null;
        
        Constructor constructor = EagerInitializedSingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        instanceTwo = (EagerInitializedSingleton) constructor.newInstance();
        
        System.out.println(instanceOne.hashCode());
        System.out.println(instanceTwo.hashCode());
    }
}

上述两个 hashCode() 值是不同的。


2、Enum Singleton(枚举式单例)

为了克服使用反射所带来的问题, Joshua Bloch 建议使用 Enum 实现单例。
因为 Java 可以保证 enum value 只会被初始化一次。
既于 enum 的值都是 public 的,这种方式可以作为单例的实现之一。

缺点:
不够灵活。
急初始化,不能懒初始化。
public enum EnumSingleton {

    INSTANCE;
    
    public static void doSomething(){
        System.out.println("do something...");
    }
}



3、Serializtion and Singleton(单例序列化)

在分布式系统中,有时候需要对单例进行序列化(实现 Serializable 接口),
以便在系统磁盘中(或网络传输中)保存单例的状态,然后在后续的某个点取得具状态的单例。

在反序列化单例时,可能会使得到的实例与原来的不同(如果单例仅仅实现 Serializable 接口)。
解决方案是重写 Serializtion API 中的 readResolve() 方法。

import java.io.Serializable;

public class SerializedSingleton implements Serializable{

    private static final long serialVersionUID = -7604766932017737115L;

    private SerializedSingleton(){}
    
    private static class SingletonHelper{
        private static final SerializedSingleton instance = new SerializedSingleton();
    }
    
    public static SerializedSingleton getInstance(){
        return SingletonHelper.instance;
    }
    
    // This will fix the de-serialization issue
    private Object readResolve() {
         // Return the available instance instead.
        return getInstance();   
    }
    
}

/*
    
    readResolve() is used for replacing the object read from the stream. 
    The only use I've ever seen for this is enforcing singletons; 
    when an object is read, replace it with the singleton instance. 
    This ensures that nobody can create another instance by serializing 
    and de-serializing the singleton.

*/


测试类:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class SerializedSingletonTest {

    public static void main(String[] args) 
            throws FileNotFoundException, IOException, ClassNotFoundException {
        SerializedSingleton instanceOne = SerializedSingleton.getInstance();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
        out.writeObject(instanceOne);
        out.close();
        
        //deserailize from file to object
        ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
        SerializedSingleton instanceTwo = (SerializedSingleton) in.readObject();
        in.close();
        
        System.out.println("instanceOne hashCode = "+instanceOne.hashCode());
        System.out.println("instanceTwo hashCode = "+instanceTwo.hashCode());
        
    }

}









-
转载请注明,
原文出处:http://lixh1986.iteye.com/blog/2351353











引用:
http://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples





-
分享到:
评论

相关推荐

    Java常用设计模式(SingleTon、FactoryMethod、AbstractFactory)

    这里我们将深入探讨三种常见的Java设计模式:单例(Singleton)、工厂方法(Factory Method)和抽象工厂(Abstract Factory)。 **单例模式(Singleton)** 单例模式确保一个类只有一个实例,并提供一个全局访问点...

    singleton设计模式java实现及对比

    Singleton设计模式是软件工程中最常用的设计模式之一,它的主要目的是确保一个类只有一个实例,并提供全局访问点。在Java中,Singleton模式的实现有多种方式,每种方式都有其优缺点,我们将详细探讨这些实现方法并...

    JAVA设计模式chm文档

    设计模式之Singleton(单态) 结构模式: 设计模式之Facade(外观) 设计模式之Proxy(代理) 设计模式之Adapter(适配器) 设计模式之Composite(组合) 设计模式之Decorator(油漆工) 设计模式之Bridge 设计模式之Flyweight(享...

    Java 单例模式Singleton

    简单的单例模式举例Singleton 分为恶汉式 懒汉式

    《java设计模式》课后习题模拟试题解答——刘伟.zip

    Java设计模式是软件工程中的一种最佳实践,它总结了在特定场景下解决常见问题的经验,为程序员提供了可重用的解决方案。本资料“《java设计模式》课后习题模拟试题解答——刘伟.zip”主要涵盖了Java设计模式的学习与...

    《Java设计模式》课后答案-刘伟.rar

    《Java设计模式》是刘伟教授的一本关于设计模式的教材,主要面向高等学校的学生和对Java编程有深入兴趣的开发者。设计模式是软件工程中的一种重要思想,它封装了在特定场景下的问题解决方案,可以提高代码的可读性、...

    Java 企业设计模式

    Java企业设计模式是软件开发领域中的重要组成部分,它是一套经过实践验证的解决方案,用于解决在Java环境中构建大型、复杂企业应用时常见的问题。这些模式是经验丰富的开发者们通过不断尝试和总结,形成的最佳实践,...

    java Singleton单例模式

    Java中的Singleton(单例模式)是一种常用的软件设计模式,它保证了类只有一个实例,并提供一个全局访问点。这种模式在需要频繁创建和销毁对象的场景中特别有用,因为它可以节省系统资源,例如数据库连接或者线程池...

    Java的Singleton模式代码(免资源分)

    Singleton模式是一种常用的设计模式,在Java中主要用于确保一个类只有一个实例,并提供一个全局访问点。这种模式对于管理共享资源(如数据库连接池、线程池等)非常有用,因为它能够有效地控制资源的创建和访问。 ...

    java设计模式&java程序设计

    ### Java设计模式与Java程序设计知识点详解 #### 一、设计模式的概念与构成要素 设计模式是一种被广泛接受的解决方案,用于解决软件设计中的常见问题。这种解决方案已经被反复验证为有效的,因此在软件开发过程中...

    23种java设计模式.pdf

    " JAVA 设计模式概述" JAVA 设计模式是指在软件设计过程中,为了提高代码的可维护性、灵活性和可扩展性所使用的一些惯用解决方案。JAVA 设计模式可以分为三种:创建模式、结构模式和行为模式。 1. 创建模式 创建...

    Java版设计模式教程

    在编程领域,设计模式是解决常见问题的经过验证的、可重用的解决方案。它们是经验丰富的软件开发人员智慧的结晶,旨在提高代码的可读性、可维护性和...现在就打开“设计模式Java版”的压缩包,开始你的设计模式之旅吧!

    《Java设计模式》课后习题参考答案-刘伟(20180723).pdf

    此外,为了确保参考资料的权威性,建议读者查阅原书《Java设计模式》以获得更加详尽的解释和说明。如果有任何意见或建议,可以通过提供的电子邮箱与作者联系。在学习设计模式的过程中,理解每一个模式的意图、结构、...

    java设计模式ppt

    ### Java设计模式详解 在软件开发领域,设计模式是一种被广泛采用的解决方案,用来解决常见的设计问题。设计模式不仅能够帮助开发者写出可复用、可维护的代码,还能提高团队间的沟通效率。以下是对给定文件中提到的...

    singleton_单例模式_java_设计模式_

    单例模式是软件设计模式中的一种经典模式,它在Java编程中被广泛使用。这个模式的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这样做的好处在于控制资源的共享,减少系统开销,以及在多线程环境中避免...

    java设计模式期末考试选择题100道

    适合Java设计模式期末考试选择题复习,形式如下: 10.(单选题)Facade(外观)模式的意图是 正确答案: A A.希望简化现有系统的使用方法,你需要定义自己的接口 B.将一个无法控制的现有对象与一个特定借口相匹配。 C....

    Java设计模式之禅

    《Java设计模式之禅》是一本深入浅出讲解设计模式的书籍,书中不仅包含23种经典设计模式的案例,还详细介绍了设计模式背后的思想和原则,适合初学者以及对设计模式有一定了解的程序员阅读。本书旨在帮助读者理解如何...

    java模式,设计模式,多种设计模式

    ### Java设计模式详解 #### 一、引言 自从J2EE(Java 2 Enterprise Edition)的出现,Java的企业级应用程序开发得到了极大的简化。然而,随着J2EE在各行各业中的广泛应用,开发人员逐渐意识到需要一种更为系统化的...

    设计模式之Singleton

    **设计模式之Singleton(单例模式)** 在软件工程中,设计模式是解决常见问题的模板,它们代表了经过时间考验的最佳实践。Singleton模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点来...

    JAVA设计模式-chm版

    Java设计模式是软件开发中的一种最佳实践,它总结了在解决特定问题时程序员们经常采用的有效方法。这个“JAVA设计模式-chm版”资源显然包含了关于Java设计模式的详细信息,便于理解和应用。设计模式是对常见问题的...

Global site tag (gtag.js) - Google Analytics