服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 高级技术 > 设计模式 > 查看文档

谨慎使用类变量及正确使用单例模式

cownew开源团队网站 http://www.cownew.com 
论坛 http://www.cownew.com/newpeng/ 
转载请注明此版权信息 
        
        昨天发现jdbmonitor在多数据源的情况下会有问题,这个问题就是对单例模式理解不深造成的。为了减少系统中的对象数目,我用单例模式设计dblogger,也就是提供一个getlogger方法返回一个日志处理器,getlogger则返回的是一个缓存了的dblogger实例。昨天我用一个大型的信息系统测试了一下,发现当有多个数据源存在的时候,所有的日志都记录到了第一个启动的jdbmonitor的配置文件指定的监听器中了。经过分析得知,虽然多个数据源启动了多个jdbmonitor,但是由于这些jdbmonitor实例是运行在同一个jvm中的,而一个类变量在同一个jvm是唯一的,所以这些实例调用getlogger的时候得到的都是第一个jdbmonitor中配置的了。
        我采用如下方式解决:为getlogger增加一个connectionid参数,将原先的单例去掉,改成一个hash表的静态变量instancemap。在调用getlogger的时候,先以connectionid为key到instancemap中找是不是已经有一个实例了,如果有则直接返回这个实例,否则构造一个dblogger,将此dblogger以connectionid为key保存到instancemap中,然后返回实例。
        根据jdbmonitor的功能特点配置文件的路径就可以做为这个connectionid了,也就是如果是多个数据源指向一个配置文件,那么这几个数据源其实还是共用一个dblogger,这个也是合理的,而且也可以节省很多资源。
        从这个例子我们可以看出,单例模式并不一定是只创建一个实例这么简单。log4j的getlogger就是很好的证明。
        但是多个数据源共用一个dblogger又引来了另一个问题,就是当有一个数据源的connection被close掉以后,dblogger也会随之close掉,其他数据源再访问的时候就会报错。我采用类似gc、com等的引用机制解决此问题。在dblogger内部维护一个计数器refcounter,初始值是0,当调用getlogger访问到此实例的时候,就refcounter自动加1,当调用dblogger的close的时候就自动减1,当refcounter降到0的时候就说明没有对象引用到它了,这个时候再释放dblogger中的各种资源。当然addref、releaseref、close等方法都要标识成synchronized的。
        同理,以前的这些channel、dblisteners类变量也要改成实例变量。consumerthread也要改成实例变量,在close中再关闭这个线程。这样就保证了每一个jdbmonitor都有自己的消费者线程。
        为了使语意更加明确,我将getlogger重命名为createlogger。
        代码已经提交到cvs,今天晚些时候将打包放到团队网站上。
        向大家汇报,sql解析引擎已经有阶段成果,强类型ast节点都已定义完毕,也已经可以生成最简单的commonast。

扫描关注微信公众号