浏览 1761 次
锁定老帖子 主题:设计模式-单例
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-06-10
最后修改:2010-09-28
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都使用了代码块同步,我们写程序的时候也要向 * 那些大师学习,尽量同步代码块. * */ } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |