4.设计模式---单例模式(上)

单例模式有一下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

根据上面单利的特点,编写一个单利模式其实很简单:

饿汉:

   

 1 package single.method;
 2 /**
 3  * 饿汉
 4  * @author zengrong
 5  *
 6  */
 7 public class eSingle {
 8     /**
 9      * 在这个类被加载时,静态变量single会被初始化,
10      * 此时类的私有构造子会被调用。这时候,单例类的唯一实例就被创建出来了。
11      */
12     private static eSingle single =new eSingle();
13     /**
14      * 私有化构造函数
15      */
16     private eSingle(){}
17     /**
18      * 对外界唯一的公开生成实例的方法
19      * @return
20      */
21     public eSingle getInESingle() {
22         return single;
23
24     }
25
26
27
28
29 }

饿汉式和他的名字一样:类一加载就生成实例:

饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。

懒汉:(线程不安全模式)


package single.method;
/**
* 懒汉式(线程不安全)
* @author zengrong
*
*/
public class lSingle {


private static lSingle single=null;

private lSingle(){}

/**
*类加载时候并不生成实例,当调用时候才去加载生成实例
* @return
*/
public static lSingle getLSingle() {
return single==null ?new lSingle():single;
}
}

 

懒汉式:时间换取空间,在类加载时候并不加载生成实例,但是在多线程情况下,二个线程几乎同时到达getLSingle()方法,这样就会产生了多个实例,违背了我们当初的想法。

解决办法,双重加锁:

 1 package single.method;
 2 /**
 3  * 改造懒汉模式变成线程安全
 4  * @author zengrong
 5  *
 6  */
 7 public class lSingleSafety {
 8     /**
 9      * 用volatile修饰的变量,
10      * 线程在每次使用变量的时候,
11      * 都会读取变量修改后的最的值。
12      * volatile很容易被误用,用来进行原子性操作。
13      */
14     private volatile static lSingleSafety singleSafety=null;
15
16
17     private lSingleSafety(){}
18     /**
19      * 采用的是双重加锁进行效率和安全
20      * @return
21      */
22     public static lSingleSafety getLSingleSafety() {
23
24         if(singleSafety==null){
25             synchronized (lSingleSafety.class) {
26                  if(singleSafety == null){
27                      singleSafety= new lSingleSafety();
28                  }
29             }
30         }
31         return singleSafety;
32     }
33
34 }

所谓“双重检查加锁”机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。

  “双重检查加锁”机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

  注意:在java1.4及以前版本中,很多JVM对于volatile关键字的实现的问题,会导致“双重检查加锁”的失败,因此“双重检查加锁”机制只只能用在java5及以上的版本。

在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括:

  1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时

  2.访问final字段时

  3.在创建线程之前创建对象时

  4.线程可以看见它将要处理的对象时

  • 类级内部类?

  简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。

  类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。

  类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。

  类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。

根据上面的这些:

那么我们是不是可以在创建一个线程安全且又不用同步锁:

 1 package single.method;
 2 /**
 3  * 使用类级别的静态类部类来进行实例化
 4  * @author zengrong
 5  *
 6  */
 7 public class StaticSingle {
 8
 9     private StaticSingle(){}
10
11     private static class SingleOnInside{
12         /**
13          * 初始化静态
14          */
15     private static StaticSingle single=new StaticSingle();
16
17     }
18
19     /**
20      * 安全问题由JVM来保证
21      * @return
22      */
23     public static StaticSingle getStaticSingle() {
24
25         return SingleOnInside.single;
26     }
27
28 }

最牛逼的方法:高效,安全

枚举:

package single.method;
/**
 * 枚举方法
 * @author zengrong
 *
 */
public enum Singleton {

      /**
     * 定义一个枚举的元素,它就代表了Singleton的一个实例。
     */

    uniqueInstance;

    /**
     * 单例可以有自己的操作
     */
    public void singletonOperation(){
        //功能处理
    }

}

单例模式的应用场景:

其中有些我也没用过,从其他博客看到的,记录下:

1. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~

2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。

4. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。

5. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。

6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。

7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

8. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。

9. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.

放在JavaWeb里讲,对于一个web项目,servletContext这个上下文对象就是单例模式的体现,因为它对应着配置文件,是全局所共享的,jsp的内置对象application也是这个道理。

对于枚举的单利模式明天继续详细分析;睡觉睡觉。。。。。

时间: 2024-10-23 04:22:11

4.设计模式---单例模式(上)的相关文章

设计模式(003) 单例模式[上] 单身懒汉

 设计模式(003) 单例模式[上] 单身懒汉 什么是单例模式(What)?    GOF:"保证一个类仅有一个实例,并且提供一个访问它的全局访问点". "嗯...,GOF通常一言九鼎,单例就是这样子的." -- OO先生边思考边说. YSJIAN  :"等等,我插一句,保证应用中一个类最多只有一个实例存在,并提供一个全局访问点访问它". 只见OO先生会心一笑. 为什么用单例模式(Why)? 从What中貌似一目了然了,GOF和YSJIAN说的都

Android 设计模式-单例模式

Android 设计模式-单例模式 什么情况下需要单例模式? 一些类提供公共功能供别人调用,本身不会处理业务逻辑 类会被许多类和线程调用 设计单例模式 public class Singleton{ private static Singleton mSingleton; private Singleton(){ } public static Singleton getInstance(){ if(mSingleton == null){ mSingleton = new Singleton(

简易的设计模式——单例模式

定义 单例模式是一种保证一个类中只有一个实例对象的软件设计模式.它需要确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 这个还是比较好理解的,一个国家只能有一个国王,不可以出现第二个,所有的人都只能来膜拜这个伟大的国王. 下面直接上代码. 实现 国王类 public class King { //确保只有一个国王 private static final King king=new King(); //保证不再产生新的国王了 private King(){} //这个国家的人通过

c#设计模式-单例模式(面试题)

c#设计模式-单例模式 单例模式三种写法: 第一种最简单,但没有考虑线程安全,在多线程时可能会出问题, public class Singleton { private static Singleton _instance = null; private Singleton(){} public static Singleton CreateInstance() { if(_instance == null) { _instance = new Singleton(); } return _in

c#设计模式-单例模式【转】

单例模式三种写法: 第一种最简单,但没有考虑线程安全,在多线程时可能会出问题 public class Singleton { private static Singleton _instance = null; private Singleton(){} public static Singleton CreateInstance() { if(_instance == null) { _instance = new Singleton(); } return _instance; } } 第

Java 设计模式 单例模式(Singleton) [ 转载 ]

Java 设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创建对象 第一种(懒汉,线程不安全): 1 public class Singleton { 2 private static Singleton instance; 3 private Singleton (){} 4 5 public static Singleton getInstan

设计模式——单例模式学习

单例模式属于设计模式中的创建模式,即创建对象时,不再由我们直接实例化对象,而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能.更好的架构优势. 1.概念 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.选择单例模式就是为了避免不一致状态.使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection). Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对

Android中的设计模式-单例模式

Android中的设计模式-单例模式 单例模式算是比较常用的模式,在Java中如果想要一个JVM中只存在某个类的一个实例,就需要使用到单例模式,而只存在一个实例的需求一般是因为: 1,对象实例比较大和复杂,创建开销很大. 2,只需要一个实例来维护整个功能的流程与交互. 例如Android中的电话应用启动时,对于单卡单待的电话,只创建一个Phone对象,用来管理RIL,CallTracker,ServiceStateTracker等对象,手机中不存在第二个Phone对象去和RILC通信. 类图 单

最简单的设计模式——单例模式的演进和推荐写法(Java 版)

前言 如下是之前总结的 C++ 版的:软件开发常用设计模式—单例模式总结(c++版),对比发现 Java 实现的单例模式和 C++ 的在线程安全上还是有些区别的. 概念不多说,没意思,我自己总结就是: 有这样一个类,该类在生命周期内有且只能有一个实例,该类必须自己创建自己的这个唯一实例,该类必须给所有其他对象提供这一实例(提供全局访问点),这样的类就叫单例类. 简单的说就是满足三个条件: 1.生命周期内有且只能有一个实例 2.自己提供这个独一无二的实例 3.该实例必须是能全局访问的 需要的考虑的

设计模式 - 单例模式之多线程调试与破坏单例

前言 在之前的 设计模式 - 单例模式(详解)看看和你理解的是否一样? 一文中,我们提到了通过Idea 开发工具进行多线程调试.单例模式的暴力破坏的问题:由于篇幅原因,现在单独开一篇文章进行演示:线程不安全的单例在多线程情况下为何被创建多个.如何破坏单例. 如果还不知道如何使用IDEA工具进行线程模式的调试,请先阅读我之前发的一篇文章: 你不知道的 IDEA Debug调试小技巧 一.线程不安全的单例在多线程情况下为何被创建多个 首先回顾简单线程不安全的懒汉式单例的代码以及测试程序代码: /**