网管联盟 | 网管论坛 | 网管u家 | 网管博客 | 网管软件 | 网管求职 | 小游戏 | 网管搜索 | 网管原创 | 网管聚合 | 网管读摘 | 网管焦点 | 世界素材 | 会员投稿 | 会员中心 
中国网管联盟
Windows Linux Cisco 网络技术 数据库 黑客攻防 DotNet Java PHP 认证 新闻资讯 服务器 存储资讯 网络设备 网管学堂 技术专题 焦点 网吧频道
 当前位置: > bitsCN.com > JAVA > 新手入门 > 基础入门 > 多线程问题导致的JDBMonitor的bug分析  

多线程问题导致的JDBMonitor的bug分析

2008-03-06  作者:bitsCN整理  来源:中国网管联盟  点评 投稿 收藏

  以前我一直是用使用数据源的系统测试JDBMonitor,昨天我准备把JDBMonitor嵌入到一个小的jsp留言板中,这个留言板写的非常简单,数据库操作也是connection随取随用、用完了就关这种最简单的形式,这倒是帮助我发现了一个超级大bug.在记事本运行中常常不规律的DataBaseDBListener的logSQL方法报空指针错误,是在logStatement.setString(1, randomGUID.toString());这一句抛出的,我跟踪到mysql驱动的内部(我使用的是mysql数据库做DataBaseDBListener的输出数据库),发现在setString的实现中会去调用connection的方法,而此时connection已经是null了,所以会报空指针错误。
 
  从其不规律的特点我判断出应该是多线程导致的问题。我跟踪发现,有的时候是先调用DataBaseDBListener的close后logSql才被调用。经过分析找出了问题所在,问题就在DBLogger中内部类LogConsumer的startConsumer方法,这个是修改以前的代码:
 
  
 for (;;)
 {
  SQLInfo info = (SQLInfo) channel.take();     中国网管论坛bbs.bitsCN.com

  if(info==null)
  {
   ontinue;
  }
  for (int i = 0, n = dbListeners.length; i < n; i++)
  {
   dbListeners[i].logSql(info);
  }

 }

 
  在调用channel.take()以后,这个SQLInfo就从channel中去除了。这时如果DBLogger的方法被调用,那么即使dbListeners[i].logSql(info)仍然在运行,但是DBLogger会认为channel已经空了,所有的dbListeners都可以被close了,而在DataBaseDBListener的close方法中会把输出目标数据库connection关掉,那么此时如果DataBaseDBListener的logSql方法还在调用的话,那么一旦使用这个connection,那么就会出现错误了。
 
  我是如下修改的:修改BlockedChannel类,去掉其take方法,增加一个peek方法和一个remove方法,peek方法是从channel中查出一个对象,但是不把它从channel中移走,只有调用remove方法后才会被移走。
 
  修改DBLogger中内部类LogConsumer的startConsumer方法为如下:
 
  
 for (;;) 网管论坛bbs_bitsCN_com
 {
  SQLInfo info = (SQLInfo) channel.peek();
  if(info==null)
  {
   continue;
  }
  for (int i = 0, n = dbListeners.length; i < n; i++)
  {
   dbListeners[i].logSql(info);
  }
  channel.remove(info);
 }

 
  在调用channel.take()以后,这个SQLInfo就从channel中去除了。这时如果DBLogger的方法被调用,那么即使dbListeners[i].logSql(info)仍然在运行,但是DBLogger会认为channel已经空了,所有的dbListeners都可以被close了,而在DataBaseDBListener的close方法中会把输出目标数据库connection关掉,那么此时如果DataBaseDBListener的logSql方法还在调用的话,那么一旦使用这个connection,那么就会出现错误了。
 
  我是如下修改的:修改BlockedChannel类,去掉其take方法,增加一个peek方法和一个remove方法,peek方法是从channel中查出一个对象,但是不把它从channel中移走,只有调用remove方法后才会被移走。 中国网管联盟bitsCN.com
 
  修改DBLogger中内部类LogConsumer的startConsumer方法为如下:
 

TAGs
 上一篇:Linux系统下JSP服务器配置步骤详解   下一篇:初学者如何开发一个高质量的J2EE系统
多线程问题导致的JDBMonitor的bug分析 评论:
loading.. 评论加载中…
评论:请自觉遵守互联网相关政策法规,评论不得超过250字。

验证码: 注册用户
本类热门排行:
最新推荐文章:
网管论坛交流: