论坛首页 Java企业应用论坛

设计模式-单例

浏览 1761 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-06-10   最后修改:2010-09-28
package com.tag2;
public class 单例模式 {

/**
* 应用场景:
*        1. 系统访问人数
*        2. 系统内部事件
*        3. 系统操作日志
*        4. 系统出错日志
*        5. 系统配置访问接口
*        ...
*        [单例主要应用于一个类只有一个实例]
* 单例模式发展.
*     *. 经典的单例模式
		public class Singleton { 
		  
		   private static Singleton instance = null; [懒汉式]
		  
		   protected Singleton() { 
		      // Exists only to defeat instantiation. 
		   } 
		   public static Singleton getInstance() { 
		      if(instance == null) { 
		         instance = new ClassicSingleton(); 
		      } 
		      return instance; 
		   } 
		}       

     * 点评:这个类只到getInstance()方法被第一次调用时才被创建,但是一般的程序是应用于多线程环境下,这个类线程不安全
     *
		public synchronized static Singleton getInstance() { 
		   if(singleton == null) {  
		      singleton = new Singleton(); 
		   } 
		   logger.info("created singleton: " + singleton); 
		   return singleton; 
		} 

     * 同步方法可以解决线程安全问题,但是同步方法开销会增大,为了整体系统的效率,尽量不要使用同步.
     *
		public  class Singleton {   
		  private static Singleton instance = new Singleton();[饿汉式]       
		}    
		public static Singleton getInstance() {   
		  return Singleton.instance;   
		} 

     * 点评:Bob Lee的写法,在类加载的时候实例就会被创建,只能通过getInstance()接口访问,能够实现线程同步
     *
     * Spring如何实现单例:
     * ApplicationContext context=FileSystemXmlApplicationContext(String configLocation)
     * ApplicationContext context=ClassPathXmlApplicationContext(String configLocation)
     * 这两个都是声名配置文件的,但是加入的是同一个域.
     * public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
}
     *  Synchronization monitor for the "refresh" and "destroy"
*  private final Object startupShutdownMonitor = new Object();
*  在对象中声名一个最终对象进行锁定,这样Application一次就只能有一个方法进入.
*  Struts如何实现单例:
		 public static Class applicationClass(String className,
	        ClassLoader classLoader)
	        throws ClassNotFoundException {
	        if (classLoader == null) {
	            // Look up the class loader to be used
	            classLoader = Thread.currentThread().getContextClassLoader();
	
	            if (classLoader == null) {
	                classLoader = RequestUtils.class.getClassLoader();
	            }
	        }
	
	        // Attempt to load the specified class
	        return (classLoader.loadClass(className));
	    }

*  这是Struts得到类加载器并加载一个类.如果类加载器为null则使用当前线程的ClassLoader
*  有人可能会问如果是多线程不是会有问题了吗?我想说的是这是通过类的反映来返回类对象,并不是所有的对象都
*  需要使用多线程支持的,毕竟多线程要处理线程同步,开销太大.
*  现在再来介绍一个Struts如何应用多线程.[Action]
*   <p>Return an <code>Action</code> instance that will be used to process
*   the current request, creating a new one if necessary.</p>
	  protected Action processActionCreate(HttpServletRequest request,
	        HttpServletResponse response, ActionMapping mapping)
	        throws IOException {
	        String className = mapping.getType();
	        Action instance;
	        synchronized (actions) {
	            // Return any existing Action instance of this class
	            instance = (Action) actions.get(className);
	
	            if (instance != null) {
	                if (log.isTraceEnabled()) {
	                    log.trace("  Returning existing Action instance");
	                }
	
	                return (instance);
	            }
	
	            // Create and return a new Action instance
	            if (log.isTraceEnabled()) {
	                log.trace("  Creating new Action instance");
	            }
	
	            try {
	                instance = (Action) RequestUtils.applicationInstance(className);
	
	                // Maybe we should propagate this exception
	                // instead of returning null.
	            } catch (Exception e) {
	                log.error(getInternal().getMessage("actionCreate",
	                        mapping.getPath()), e);
	
	                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
	                    getInternal().getMessage("actionCreate", mapping.getPath()));
	
	                return (null);
	            }
	
	            actions.put(className, instance);
	
	            if (instance.getServlet() == null) {
	                instance.setServlet(this.servlet);
	            }
	        }
	
	        return (instance);
		}      
 
*  点评:actions是一个HashMap实例,这里使用同步代码块的方法synchronized(actions)[注意:同步代码块比同步方法开销小]
*  当一个请求过来时[线程],这里使用了同步,每一次都从actions中得到对象.如果不为空,则返回,如果为空则通过反映生成对象并返回.
*  这其实也属于单例注册.
*  上面介绍了Spring对应多个配置文件时用的同步,Struts的核心Action的同步,下面介绍一个Spring的核心Bean是如何实现单例的.

*  Return the (raw) singleton object registered under the given name,
*  creating and registering a new one if none registered yet.
	 public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			// Re-check singleton cache within synchronized block.
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);//singletonsCurrentlyInCreation,同步的集合,添加BeanName
				try {
					singletonObject = singletonFactory.getObject();//返回这个对象.
				}
				finally {
					afterSingletonCreation(beanName);//singletonsCurrentlyInCreation.同步的集合中,移除BeanName
				}
				addSingleton(beanName, singletonObject);//添加对象到singletonObjects
			}
			return (singletonObject != NULL_OBJECT ? singletonObject : null);
		}
	 }
 
* 细心的读者会发现,Struts和Spring都是采用单例注册器的方式实现的.
* private final Map singletonObjects = CollectionFactory.createConcurrentMapIfPossible(16);
* 这里根据你的jdk版本判断使用哪种同步Map
* if  JDKVersion>JAVA_15[或者包括edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap]
*                               new ConcurrentHashMap(initialCapacity)
*                          else
*                               Collections.synchronizedMap(new HashMap(initialCapacity));
* 如果单例注册器中没有此对象
	 *                  1. beforeSingletonCreation(beanName); //监视创建对象前
	 *                  2. singletonObject = singletonFactory.getObject();//返回对象
	 *singletonFactory.getObject();这是接口方法,这个接口由程序在调用的时候实现.

	 *getSingleton(beanName, new ObjectFactory() {
					public Object getObject() throws BeansException {
						try {
							return createBean(beanName, mbd, args);//创建方法就是在子类要重写的
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					}
	  });
	 *                 3.afterSingletonCreation(beanName);//监视创建对象后
	 *                 4.addSingleton(beanName, singletonObject);//添加对象到singletonObjects
	 *                 5.返回该对象.
	 * 综上所述:在应用于系统资源时,为了提供同一接口,需要同步信息,但是Struts和Spring都使用了代码块同步,我们写程序的时候也要向
	 * 那些大师学习,尽量同步代码块.
	 *  
	 */
	 
	
}



论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics