`
tiger82
  • 浏览: 1548 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论
阅读更多

基本概念

Singleton 是一种创建性模型,它用来确保只产生一个实例,并提供一个访问它的全局访问点.对一些类来说,保证只有一个实例是很重要的,比如有的时候,数据库连接或 Socket 连接要受到一定的限制,必须保持同一时间只能有一个连接的存在.再举个例子,集合中的 set 中不能包含重复的元素,添加到set里的对象必须是唯一的,如果重复的值添加到 set,它只接受一个实例.JDK中正式运用了Singleton模式来实现 set 的这一特性,大家可以查看java.util.Collections里的内部静态类SingletonSet的原代码.其实Singleton是最简单但也是应用最广泛的模式之一,在 JDK 中随处可见.


简单分析

为了实现 Singleton 模式,我们需要的是一个静态的变量,能够在不创建对象的情况下记忆是否已经产生过实例了.静态变量或静态方法都可以在不产生具体实例的情况下直接调用,这样的变量或方法不会因为类的实例化而有所改变.在图1的结构中可以看到,uniqueInstance 就是这个独立的静态变量,它可以记忆对象是否已经实例化了,在静态方法 Instance 中对这个变量进行判断,若没有实例化过就产生一个新的对象,如果已经实例化了则不再产生新的对象,仍然返回以前产生的实例.


图1: Singleton 模式结构
图1: Singleton 模式结构


具体实施

实现 Singleton 模式的办法通常有三种.

一. 用静态方法实现 Singleton 这种方法是使用静态方法来监视实例的创建.为了防止创建一个以上的实例,我们最好把构造器声明为 private.

这样可以防止客户程序员通过除由我们提供的方法之外的任意方式来创建一个实例,如果不把构造器声明为private,编译器就会自作聪明的自动同步一个默认的friendly构造器.这种实现方法是最常见的,也就是图1中结构的标准实现.

public class Singleton {  
  private static Singleton s; 
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    if (s == null)
      s = new Singleton();
    return s;
  }
}
// 测试类
class singletonTest {
  public static void main(String[] args) {
    Singleton s1 = Singleton.getInstance();
    Singleton s2 = Singleton.getInstance();
    if (s1==s2)
      System.out.println("s1 is the same instance with s2");
    else
      System.out.println("s1 is not the same instance with s2");
  }
}

 

singletonTest运行结果是:

s1 is the same instance with s2

这证明我们只创建了一个实例.

二. 以静态变量为标志实现 Singleton 在类中嵌入一个静态变量做为标志,每次都在进入构造器的时候进行检查.

问题在于构造器没有返回类型,如果确定创建一个实例成功与否.一个方法是调用一个函数来检查创建是否成功,然后简单的返回一个来自静态变量的值,但是这样 做是不优雅的,而且容易发生错误.比较好的做法是创建一个当创建了一个以上的实例时可以抛出异常的类,这个类仅仅是调用父类方法,好处是用了自己命名的异 常类型,错误信息更加清晰:

class SingletonException extends RuntimeException {
  public SingletonException(String s) {
    super(s);
  }
}
class Singleton {
  static boolean instance_flag = false; // true if 1 instance
  public Singleton() {
    if (instance_flag)
      throw new SingletonException("Only one instance allowed");
    else
      instance_flag = true; // set flag for 1 instance
  }
}
// 测试类
public class singletonTest {
  static public void main(String argv[]) {
    Singleton s1, s2;
    // create one incetance--this should always work
    System.out.println("Creating one instance");
    try {
      s1 = new Singleton();
    } catch (SingletonException e) {
      System.out.println(e.getMessage());
    }
    // try to create another spooler --should fail
    System.out.println("Creating two instance");
    try {
      s2 = new Singleton();
    } catch (SingletonException e) {
      System.out.println(e.getMessage());
    }
  }
}

 

singletonTest运行结果是:

Creating one instance

Creating two instance

Only one instance allowed

可以看出,第一个实例顺利创建,第二个实例创建实抛出了我们自定义的异常.

三. 用注册器机制来创建 Singleton 首先用集合中的Hashtable 和Enumeration来实现addItem(Object key, Object value),getItem(Object key), ,removeItem(Object key)等方法实现一个管理器,将key和value一一关联起来,客户程序员创建实例前首先用addItem方法进行注册,再用getItem方法获取 实例.Hashtable中的key是唯一的,从而保证创建的实例是唯一的,具体实现限于篇幅不再细说,在Prototype模型的应用一文中我将会给出 一个实现注册器的代码.用注册器机制来创建 Singleton模式的好处是易于管理,可以同时控制多个不同类型的Singleton 实例.


小结

 

  1. Singleton模式可以方便的进行扩充,产生指定数目的实例.
  2. 在The Design Patterns Java Companion 一书中曾提到过用静态类的方式来实现 Singleton模式,并指出java.lang.Math就是一个例子,这里我并不表示赞同,因为Math并不是一个真正的对象,我们只是直接调用 Math类所包装的静态方法而已,根本就没有创建实例的过程,又从何说起只产生一个实例呢?这个问题我曾到Javaranch的论坛上发过帖子,所有回帖 的人也都是对这一观点持否定态度.
  3. 在多线程的程序中,singleton可能会变的不可靠,可能会出现多个实例,解决的办法很简单,加个同步修饰符: public static synchronized Singleton getInstance(). 这样就保证了线程的安全性.
  4. 最后要说的是大家可能会看见一些其他实现Singleton模式的方法,因为模式在具体的应用时是灵活的,不是一成不变的,并没有一个固定的做法,但大都是上面几种方法的变形.
分享到:
评论
13 楼 neo_q 2011-01-30  
关于DCL这里有很详细的介绍和解释,wish to help。http://www.iteye.com/topic/875420
12 楼 aabcc 2011-01-28  
看这帖时候我就知道又有人讨论DCL,我是不是开始有第六感了。
11 楼 Crusader 2011-01-28  
chenyong0214 写道
Crusader 写道
public class Singleton {

	private volatile static Singleton singleton;
	
	private Singleton(){ }
	
	public static Singleton getInstance(){
		// 双重检查加锁
		if(singleton==null){
			synchronized(Singleton.class){
				// 延迟实例化,需要时才创建
				if(singleton==null)
					singleton = new Singleton();
			}
		}
		return singleton;
	}
}



好像有几篇文章论述了java中DCL不可实现


为什么不能实现双重加锁,望详细说说
10 楼 wu_quanyin 2011-01-28  
<div class="quote_title">yangguo 写道</div>
<div class="quote_div">
<div class="quote_title">whaosoft 写道</div>
<div class="quote_div">
<div class="quote_title">my_niuniu 写道</div>
<div class="quote_div">
<div class="quote_title">lyw985 写道</div>
<div class="quote_div">
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>
</div>
<p>正解。楼主的方法线程不安全,需要在方法上加同步,但会严重影响效率。</p>
</div>
<p>这个方法那你得但愿类加载器是一个。。</p>
</div>
<p> </p>
<p>95%都是一个,蛋疼才去加几个。</p>
</div>
<p>你都 用95%了,一点都不肯定,,,那不是有时你蛋疼。。。</p>
9 楼 chenyong0214 2011-01-28  
Crusader 写道
public class Singleton {

	private volatile static Singleton singleton;
	
	private Singleton(){ }
	
	public static Singleton getInstance(){
		// 双重检查加锁
		if(singleton==null){
			synchronized(Singleton.class){
				// 延迟实例化,需要时才创建
				if(singleton==null)
					singleton = new Singleton();
			}
		}
		return singleton;
	}
}



好像有几篇文章论述了java中DCL不可实现
8 楼 penghuaiyi 2011-01-28  
<div class="quote_title">daxiong294 写道</div>
<div class="quote_div">
<div class="quote_title">my_niuniu 写道</div>
<div class="quote_div">
<div class="quote_title">lyw985 写道</div>
<div class="quote_div">
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>
</div>
<p>正解。楼主的方法线程不安全,需要在方法上加同步,但会严重影响效率。</p>
</div>
<p><br>这一段按照楼主的写法比较好点,实例化单例放在getInstance()方法中。</p>
</div>
<p>单例模式最佳写法(没有线程安全问题):</p>
<pre name="code" class="java">public class Singleton { 
  private static class SingletonHolder{
       final static Singleton  instance= new Singleton ();
  }
  private Singleton(){};

  public static Singleton getInstance() {
        return SingletonHolder.instance;
  }

}</pre>
<p> </p>
<p> JVM加载类不会产生线程安全问题,即两个线程同时去加载这个类,也会按顺序加载,因此会保存SingletonHolder实例的唯一性</p>
7 楼 wujiazhao88 2011-01-28  
加个final吧
6 楼 Crusader 2011-01-28  
public class Singleton {

	private volatile static Singleton singleton;
	
	private Singleton(){ }
	
	public static Singleton getInstance(){
		// 双重检查加锁
		if(singleton==null){
			synchronized(Singleton.class){
				// 延迟实例化,需要时才创建
				if(singleton==null)
					singleton = new Singleton();
			}
		}
		return singleton;
	}
}
5 楼 daxiong294 2011-01-28  
<div class="quote_title">my_niuniu 写道</div>
<div class="quote_div">
<div class="quote_title">lyw985 写道</div>
<div class="quote_div">
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>
</div>
<p>正解。楼主的方法线程不安全,需要在方法上加同步,但会严重影响效率。</p>
</div>
<p><br>这一段按照楼主的写法比较好点,实例化单例放在getInstance()方法中。</p>
4 楼 yangguo 2011-01-28  
<div class="quote_title">whaosoft 写道</div>
<div class="quote_div">
<div class="quote_title">my_niuniu 写道</div>
<div class="quote_div">
<div class="quote_title">lyw985 写道</div>
<div class="quote_div">
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>
</div>
<p>正解。楼主的方法线程不安全,需要在方法上加同步,但会严重影响效率。</p>
</div>
<p>这个方法那你得但愿类加载器是一个。。</p>
</div>
<p> </p>
<p>95%都是一个,蛋疼才去加几个。</p>
3 楼 whaosoft 2011-01-27  
<div class="quote_title">my_niuniu 写道</div>
<div class="quote_div">
<div class="quote_title">lyw985 写道</div>
<div class="quote_div">
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>
</div>
<p>正解。楼主的方法线程不安全,需要在方法上加同步,但会严重影响效率。</p>
</div>
<p>这个方法那你得但愿类加载器是一个。。</p>
2 楼 my_niuniu 2011-01-27  
<div class="quote_title">lyw985 写道</div>
<div class="quote_div">
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>
</div>
<p>正解。楼主的方法线程不安全,需要在方法上加同步,但会严重影响效率。</p>
1 楼 lyw985 2011-01-27  
<p>单例代码如下:</p>
<p> </p>
<pre name="code" class="java">public class Singleton { 
  private static Singleton s=new Singleton();
  private Singleton(){};
  /**
   * Class method to access the singleton instance of the class.
   */
  public static Singleton getInstance() {
    return s;
  }
}</pre>
<p> 完全不用考虑同步问题</p>

相关推荐

    Java 单例模式.pptx

    ### Java 单例模式详解 #### 一、什么是单例模式? 单例模式是一种常用的软件设计模式,在这种模式中,一个类只能拥有一个实例,并且该类必须自行创建并提供这个实例。通常,单例模式用于确保某个类在整个应用程序...

    java单例模式实例

    在Java中,有多种实现单例模式的方法,每种都有其特点和适用场景。接下来,我们将深入探讨这些实现方式。 首先,我们来看**懒汉式(Lazy Initialization)**。这种实现方式是在类被首次请求时才创建单例对象,延迟...

    使用Java单例模式实现一个简单的日志记录器.txt

    ### 使用Java单例模式实现一个简单的日志记录器 #### 一、单例模式简介 单例模式是一种常用的软件设计模式,在该模式中,一个类只能创建一个实例,并且提供了一个全局访问点来访问该实例。单例模式的主要优点包括...

    Java 单例模式 懒汉模式

    Java 单例模式 懒汉模式 //懒汉式 多线程中不可以保证是一个对象

    Java 单例模式 工具类

    Java中的单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供全局访问点。在Java编程中,单例模式常用于控制资源的访问,比如数据库连接池、线程池或者日志对象等。本篇文章将深入探讨如何在Java中...

    JAVA单例模式的几种实现方法

    ### JAVA单例模式的几种实现方法 #### 一、饿汉式单例类 饿汉式单例类是在类初始化时就已经完成了实例化的操作。这种实现方式简单且线程安全,因为实例化过程是在编译期间完成的,不会受到多线程的影响。 **代码...

    Java单例模式设计

    Java单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供全局访问点。这种模式在需要频繁创建和销毁对象的场景中,或者当对象昂贵时(如数据库连接),能够节省系统资源,提高效率。本篇文章将深入探讨...

    java单例模式及实现

    Java单例模式及实现 Java单例模式是一种常见的设计模式,确保某一个类只有一个实例,而且向这个系统提供这个实例。单例模式可以分为三种:懒汉式单例、饿汉式单例、登记式单例。 单例模式的要点 1. 某个类只能有...

    Java单例模式深入理解

    Java单例模式是一种设计模式,它允许在程序中创建唯一一个类实例,通常用于管理共享资源,例如数据库连接、线程池或者配置对象等。单例模式的核心在于限制类的构造函数,确保类只能被初始化一次,从而实现全局唯一的...

    Java单例模式应用研究.pdf

    ### Java单例模式应用研究 #### 一、单例模式概述 单例模式(Singleton Pattern)作为一种最基本的创建型设计模式,其主要目的是控制一个类的实例化过程,确保在整个应用程序中仅存在一个实例,并且该实例能够被全局...

    java单例模式的例子

    Java单例模式是一种常见的设计模式,它在软件工程中用于控制类的实例化过程,确保一个类只有一个实例,并提供一个全局访问点。这种模式在系统资源管理、缓存、日志记录等方面应用广泛。下面我们将深入探讨Java单例...

    Java单例模式的全面总结

    Java中的单例模式主要分为三种实现方式:懒汉式单例、饿汉式单例和登记式单例。 1. 懒汉式单例(Lazy Initialization) 懒汉式单例的特点是在类被加载时不创建实例,而是在首次调用`getInstance()`方法时才进行实例...

    java单例模式连接数据库源码

    Java单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在数据库连接管理中,使用单例模式能有效控制资源,避免频繁创建和关闭数据库连接导致的性能损失和资源浪费。以下是对Java单例模式...

    java单例模式代码实例

    Java单例模式是一种常用的设计模式,它用于保证一个类只有一个实例,并提供全局访问点。这种模式在系统资源有限或者需要共享昂贵对象时尤其有用,比如数据库连接池、线程池等。下面我们将深入探讨Java单例模式的实现...

    java 单例模式(懒汉式与饿汉式).docx

    java 单例模式(懒汉式与饿汉式) java 单例模式是一种常用的软件设计模式。在它的可信结构中只包含一个被实例化单例的特别类。通过单例设计模式可以把整系统中的一个类只有一个实例。单例设计模式又分为两种方式,...

    Java单例模式.pdf

    Java单例模式是设计模式中的一种,在软件开发中扮演着重要的角色。单例模式的目的是保证一个类仅有一个实例,并且提供一个全局访问点。在Java中实现单例模式有多种方法,主要包括懒汉式、饿汉式、注册式(使用容器)...

Global site tag (gtag.js) - Google Analytics