单例模式介绍.docx

上传人:小飞机 文档编号:3346288 上传时间:2023-03-12 格式:DOCX 页数:9 大小:39.96KB
返回 下载 相关 举报
单例模式介绍.docx_第1页
第1页 / 共9页
单例模式介绍.docx_第2页
第2页 / 共9页
单例模式介绍.docx_第3页
第3页 / 共9页
单例模式介绍.docx_第4页
第4页 / 共9页
单例模式介绍.docx_第5页
第5页 / 共9页
亲,该文档总共9页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《单例模式介绍.docx》由会员分享,可在线阅读,更多相关《单例模式介绍.docx(9页珍藏版)》请在三一办公上搜索。

1、单例模式介绍1 单例模式:单例模式确保某一个类只有一个 实例,而且该类只能是自己 实例化自己并向其他类公开 这个实例的对象创建 模式 采用单例模式的类:根据单例模式知道其要满足以下三点 1. 确保某一个类只有一个实例 2. 而且自己实例化 3. 并向其他类提供这个实例类 。 2 确保以上三点的所采用的编程策略 * 把构造方法声明为Private。确保只能由自己创建,避免外部创建实例或者被子类继承从而创造额外实例; * 定义一个私有静态的该类的实例作为该类的数据域。确保一个类只能有一个实例; *定义一个静态 工厂方法。外部类不能实例化一个该类的对象,所以只能用Static 的方法,提供给其他类调

2、用,返回此单例类唯一的实例。 3、使用单例模式的条件: 使用单例模式有一个必要条件:在一个系统要求一个类只有一个实例时才应当使用单例模式,反过来说,如果一个类可以有几个实例共存,那么就没有必要使用单例模式类。 4 单例在JAVA中的3种形式 主动式单例类: public class ActiveSingleton private static final ActiveSingleton m_instance = new ActiveSingleton ; / 在类加载的时候就实例化一个自己的对象 private ActiveSingleton /每次调用该工厂方法返回该实例 public st

3、atic ActiveSingleton getInstance return m_instance; java语言中单例类的一个最重要的特点是类的构造方法是私有的,从而避免外界利用构造子直接创建出任意多的实例。因为构造是私有的,因此此类不能被继承。主动式单例类在类加载的时候就实例化一个自己的对象。 被动式单例类: public class LazySingleton private static LazySingleton m_instance = null; private LazySingleton /静态工厂方法, 在第一次被调用时才将自己实例化 synchronized public

4、 static LazySingleton getInstance if (m_instance = null) m_instance = new LazySingleton; return m_instance; 与主动式单例类相同的是,被动式单例类的构造方法是私有的,不同的是在第一次被引用时才将自己实例化,如果加载器是静态的,那么在被动式单例类被加载时不会将自己实例化。 登记式单例类: 登记式单例这个单例实际上维护的是一组单例类的实例,将这些实例存放在一个Map中,对于已经登记过的实例,则从工厂直接返回,对于没有登记的,则先登记,而后返回。 public class RegSingleto

5、n private static HashMap m_registry = new HashMap; static RegSingleton x = new RegSingleton; m_registry.put(x.getClass.getName, x); protected RegSingleton public static RegSingleton getInstance(String name) if (name = null) name = RegSingleton; if (m_registry.get(name) = null) try m_registry.put(nam

6、e, Class.forName(name).newInstance); catch (Exception e) System.out.println(Error happened.); return (RegSingleton) (m_registry.get(name); / 一个测试方法 public String about return Hello, I am RegSingleton; / 登记式单例类的子类 public class RegSingletonChild extends RegSingleton public RegSingletonChild / 静态工厂方法 p

7、ublic static RegSingletonChild getInstance return (RegSingletonChild)RegSingleton.getInstance(RegSingleton) public String about return Hello, I am RegSingletonChild; 单例对象是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。正是由于这个特点,单例对象通常作为程序中的存放配置信息的载体,因为它能保证其他对象读到一致的信息。例如在某个服务器程序中,该服务器的配置信息可能存放在数据库或文件中,

8、这些配置数据由某个单例对象统一读取,服务进程中的其他对象如果要获取这些配置信息,只需访问该单例对象即可。这种方式极大地简化了在复杂环境下,尤其是多线程环境下的配置管理,但是随着应用场景的不同,也可能带来一些同步问题。 本文将探讨一下在多线程环境下,使用单例对象作配置信息管理时可能会带来的几个同步问题,并针对每个问题给出可选的解决办法。 问题描述 在多线程环境下,单例对象的同步问题主要体现在两个方面,单例对象的初始化和单例对象的属性更新。 本文描述的方法有如下假设: 1. 单例对象的属性的获取,是通过单例对象的初始化实现的。也就是说,在单例对象初始化时,会从文件或数据库中读取最新的配置信息。 2

9、. 其他对象不能直接改变单例对象的属性,单例对象属性的变化来源于配置文件或配置数据库数据的变化。 1.1 单例对象的初始化 首先,讨论一下单例对象的初始化同步。单例模式的通常处理方式是,在对象中有一个静态成员变量,其类型就是单例类型本身;如果该变量为null,则创建该单例类型的对象,并将该变量指向这个对象;如果该变量不为null,则直接使用该变量。 其过程如下面代码所示: public class GlobalConfig private static GlobalConfig instance = null; private Vector properties = null; private

10、 GlobalConfig /Load configuration information from DB or file /Set values for properties public static GlobalConfig getInstance if (instance = null) instance = new GlobalConfig; return instance; public Vector getProperties return properties; 这种处理方式在单线程的模式下可以很好的运行;但是在多线程模式下,可能产生问题。如果第一个线程发现成员变量为null,

11、准备创建对象;这是第二个线程同时也发现成员变量为null,也会创建新对象。这就会造成在一个JVM中有多个单例类型的实例。如果这个单例类型的成员变量在运行过程中变化,会造成多个单例类型实例的不一致,产生一些很奇怪的现象。例如,某服务进程通过检查单例对象的某个属性来停止多个线程服务,如果存在多个单例对象的实例,就会造成部分线程服务停止,部分线程服务不能停止的情况。 1.2 单例对象的属性更新 通常,为了实现配置信息的实时更新,会有一个线程不停检测配置文件或配置数据库的内容,一旦发现变化,就更新到单例对象的属性中。在更新这些信息的时候,很可能还会有其他线程正在读取这些信息,造成意想不到的后果。还是以

12、通过单例对象属性停止线程服务为例,如果更新属性时读写不同步,可能访问该属性时这个属性正好为空,程序就会抛出异常。 解决方法 2.1 单例对象的初始化同步 对于初始化的同步,可以通过如下代码所采用的方式解决。 public class GlobalConfig private static GlobalConfig instance = null; private Vector properties = null; private GlobalConfig /Load configuration information from DB or file /Set values for proper

13、ties private static synchronized void syncInit if (instance = null) instance = new GlobalConfig; public static GlobalConfig getInstance if (instance = null) syncInit; return instance; public Vector getProperties return properties; 这种处理方式虽然引入了同步代码,但是因为这段同步代码只会在最开始的时候执行一次或多次,所以对整个系统的性能不会有影响。 2.2 单例对象的

14、属性更新同步 为了解决第2个问题,有两种方法: 1,参照读者/写者的处理方式 设置一个读计数器,每次读取配置信息前,将计数器加1,读完后将计数器减1.只有在读计数器为0时,才能更新数据,同时要阻塞所有读属性的调用。代码如下。 public class GlobalConfig private static GlobalConfig instance; private Vector properties = null; private boolean isUpdating = false; private int readCount = 0; private GlobalConfig /Load

15、 configuration information from DB or file /Set values for properties private static synchronized void syncInit if (instance = null) instance = new GlobalConfig; public static GlobalConfig getInstance if (instance=null) syncInit; return instance; public synchronized void update(String p_data) syncUp

16、dateIn; /Update properties private synchronized void syncUpdateIn while (readCount 0) try wait; catch (Exception e) private synchronized void syncReadIn readCount+; private synchronized void syncReadOut readCount-; notifyAll; public Vector getProperties syncReadIn; /Process data syncReadOut; return

17、properties; 2,采用影子实例的办法 具体说,就是在更新属性时,直接生成另一个单例对象实例,这个新生成的单例对象实例将从数据库或文件中读取最新的配置信息;然后将这些配置信息直接赋值给旧单例对象的属性。如下面代码所示。 public class GlobalConfig private static GlobalConfig instance = null; private Vector properties = null; private GlobalConfig /Load configuration information from DB or file /Set values

18、for properties private static synchronized void syncInit if (instance = null) instance = new GlobalConfig; public static GlobalConfig getInstance if (instance = null) syncInit; return instance; public Vector getProperties return properties; public void updateProperties /Load updated configuration information by new a GlobalConfig object GlobalConfig shadow = new GlobalConfig; properties = shadow.getProperties; 注意:在更新方法中,通过生成新的GlobalConfig的实例,从文件或数据库中得到最新配置信息,并存放到properties属性中。 上面两个方法比较起来,第二个方法更好,首先,编程更简单;其次,没有那么多的同步操作,对性能的影响也不大。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号