单例模式分享

来源:互联网 发布:ubuntu 启动项 编辑:程序博客网 时间:2024/05/21 17:47

单例模式分享

特点:

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

优点:
1:可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection);对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。 

缺点: 

1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。 

2、单例类的职责过重,在一定程度上违背了单一职责原则(一个类只负责一项职责)” 

3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失

  

单例模式有很多种,首先顺手写一个。 

(饿汉模式)

1. public final class EagerSingleton  

2. {  

3.     private static EagerSingleton singObj = new EagerSingleton();  

4.   

5.     private EagerSingleton(){  

6.     }  

7.   

8.     public static EagerSingleton getSingleInstance(){  

9.        return singObj

10.     }  

11. }  

 (饿汉模式--变种)

 

1. public class Singleton {  

2.     private Singleton instance = null;  

3.     static {  

4.     instance = new Singleton();  

5.     }  

6.     private Singleton (){}  

7.     public static Singleton getInstance() {  

8.     return this.instance;  

9.     }  

10. }  

这种写法就是所谓的饿汉模式,每个对象在没有使用之前就已经初始化了。这就可能带来潜在的性能问题:如果这个对象很大呢?没有使用这个对象之前,就把它加载到了内存中去是一种巨大的浪费。

针对这种情况,我们可以对以上的代码进行改进,使用一种新的设计思想——延迟加载(Lazy-load Singleton)。 

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

1. public final class LazySingleton  

2. {  

3.     private static LazySingleton singObj = null;  

4.   

5.     private LazySingleton(){  

6.     }  

7.   

8.     public static LazySingleton getSingleInstance(){  

9.         if(null == singObj ) singObj = new LazySingleton();

10.           return singObj

11.     }  

12. }  

 这种写法就是所谓的懒汉模式。它使用了延迟加载来保证对象在没有使用之前,是不会进行初始化的。但是,这种写法线程不安全。这是因为在多个线程可能同时运行到第九行,判断singObjnull,于是同时进行了初始化。

所以,这时面临的问题是如何使得这个代码线程安全?很简单,在那个方法前面加一个SynchronizedOK了。

(懒汉模式,线程安全) 

1. public final class ThreadSafeSingleton  

2. {  

3.     private static ThreadSafeSingleton singObj = null;  

4.   

5.     private ThreadSafeSingleton(){  

6.     }  

7.   

8.     public static Synchronized ThreadSafeSingleton getSingleInstance(){  

9.         if(null == singObj ) singObj = new ThreadSafeSingleton();

10.             return singObj

11.     }  

12. }   

  这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,同步的代价必然会一定程度的使程序的并发度降低。出一种新的设计思想——双重检查锁(Double-Checked Lock)。

(双重检查锁) 

1. public final class DoubleCheckedSingleton  

2. {  

3.     private static DoubleCheckedSingletonsingObj = null;  

4.   

5.     private DoubleCheckedSingleton(){  

6.     }  

7.   

8.     public static DoubleCheckedSingleton getSingleInstance(){  

9.         if(null == singObj ) {

10.               Synchronized(DoubleCheckedSingleton.class){

11.                      if(null == singObj)

12.                            singObj = new DoubleCheckedSingleton();

13.               }

14.          }

15.        return singObj

16.     }  

17. }

jdk1.5之后才能正常达到单例效果。

Initialization on Demand Holder -静态内部类)

1. public class Singleton {  

2.     private static class SingletonHolder {  

3.     private static final Singleton INSTANCE = new Singleton();  

4.     }  

5.     private Singleton (){}  

6.     public static final Singleton getInstance() {  

7.     return SingletonHolder.INSTANCE;  

8.     }  

9. } 

 这种方法使用内部类来做到延迟加载对象,在初始化这个内部类的时候,JLS(Java Language Sepcification)会保证这个类的线程安全。这种写法最大的美在于,完全使用了Java虚拟机的机制进行同步保证,没有一个同步的关键字。

(枚举类型)

   public enum Singleton {  
    INSTANCE {  
        public void someMethod() {  
            // . . .  
        }  
    };    
    protected abstract void someMethod();  
   }

 

懒汉模式和饿汉模式的优缺点:

对于懒汉模式,我们可以这样理解:该单例类非常懒,只有在自身需要的时候才会行动,
从来不知道及早做好准备。它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象,
然后返回,如果已有对象就不再创建,立即返回。 懒汉模式只在外部对象第一次请求实例的时候才去创建。

懒汉模式,它的特点是运行时获得对象的速度比较慢,但加载类的时候比较快。它在整个应用的生命周期只有一部分时间在占用资源。

对于饿汉模式,我们可以这样理解:该单例类非常饿,迫切需要吃东西,所以它在类加载的时候就立即创建对象。

饿汉模式,它的特点是加载类的时候比较慢,但运行时获得对象的速度比较快。它从加载到应用结束会一直占用资源。

这 两种模式对于初始化较快,占用资源少的轻量级对象来说,没有多大的性能差异,选择懒汉式还是饿汉式都没有问题。
但是对于初始化慢,占用资源多的重量级对象 来说,就会有比较明显的差别了。所以,对重量级对象应用饿汉模式,类加载时速度慢,
但运行时速度快;懒汉模式则与之相反,类加载时速度快,但运行时第一次 获得对象的速度慢。 
从用户体验的角度来说,我们应该首选饿汉模式。我们愿意等待某个程序花较长的时间初始化,
却不喜欢在程序运行时等待太久,给人一种反应迟钝的感觉,所以对于有重量级对象参与的单例模式, 我们推荐使用饿汉模式 。 
而 对于初始化较快的轻量级对象来说,选用哪种方法都可以。如果一个应用中使用了大量单例模式,我们就应该权衡两种方法了。
轻量级对象的单例采用懒汉模式,减 轻加载时的负担,缩短加载时间,提高加载效率;同时由于是轻量级对象,把这些对象的创建放在使用时进行,
实际就是把创建单例对象所消耗的时间分摊到整个应 用中去了,对于整个应用的运行效率没有太大影响。

 

什么情况下使用单例模式?
比如,Spring框架、Struts框架、数据库连接池的设计一般采用单例模式。

SpringIOC容器对bean的管理

http://blog.csdn.net/xiaojianpitt/article/details/6650280

Spring 单例BeanJava 单例模式的区别

Spring的的单例是基于BeanFactory也就是spring容器,单例Bean在此Spring容器内是单个的,Java的单例是基于JVM,每个JVM内一个单例。

 

Struts

"Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 
"Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)

Action执行的控制: 
Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 
Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

 

0 0
原创粉丝点击