如鵬網(wǎng) 大學(xué)生計(jì)算機(jī)學(xué)習(xí)社區(qū)

          CowNew開源團(tuán)隊(duì)

          http://www.cownew.com 郵件請(qǐng)聯(lián)系 about521 at 163.com

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            363 隨筆 :: 2 文章 :: 808 評(píng)論 :: 0 Trackbacks

          作者楊中科是CowNew開源團(tuán)隊(duì)JDBMonitor項(xiàng)目組的開發(fā)人員。
          CowNew開源團(tuán)隊(duì)網(wǎng)站 http://www.cownew.com
          論壇 http://www.cownew.com/newpeng/
          轉(zhuǎn)載請(qǐng)注明此版權(quán)信息

          數(shù)據(jù)庫(kù)監(jiān)控、日志工具JDBMonitor在介紹文檔中說到“JDBMonitor另起一個(gè)線程來記錄SQL,所以它不會(huì)對(duì)程序運(yùn)行速度有任何影響。”,那么它是如何做到的呢?
          JDBMonitor采用“生產(chǎn)者-消費(fèi)者模型”完成此功能。學(xué)過操作系統(tǒng)原理的朋友對(duì)“生產(chǎn)者-消費(fèi)者模型”一定不陌生,它是和“哲學(xué)家進(jìn)餐問題”等相提并論的經(jīng)典模型。
          JDBMonitor的主線程做為“生產(chǎn)者”,產(chǎn)生“日志信息”這個(gè)產(chǎn)品,另起一個(gè)線程做為消費(fèi)者,這個(gè)消費(fèi)者負(fù)責(zé)“消費(fèi)”日志信息,并把日志信息派發(fā)給所有的監(jiān)聽者,這樣日志的產(chǎn)生和消費(fèi)是獨(dú)立的,所以無論日志的派發(fā)有多慢,都沒有關(guān)系,都不會(huì)影響到主線程的運(yùn)行速度。下面讓我們深入研究一下:
          (注:JDBMonitor的二進(jìn)制jar包和源代碼都可以從 http://www.cownew.com 下載得到。)
          打開com.cownew.JDBMonitor.common.DBLogger。JDBMonitor每次截獲到一條sql語句,都會(huì)調(diào)用logSQL方法,并把sql語句的信息對(duì)象傳過來,這樣我們就可以把logSQL方法當(dāng)成生產(chǎn)者,logsql把消息放到channel中。LogConsumer是一個(gè)實(shí)現(xiàn)了Runnable接口的類,它就是日志的消費(fèi)者,并且是運(yùn)行于另一個(gè)線程的,它負(fù)責(zé)實(shí)時(shí)檢測(cè)channel,只要channel中有東西,他就從channel取出日志對(duì)象,然后發(fā)送給各個(gè)監(jiān)聽器。
          startConsumer中
          for (;;)
          {
          ? SQLInfo info = (SQLInfo) channel.take();
          ? for (int i = 0, n = dbListeners.length; i < n; i++)
          ? {
          ??? dbListeners[i].logSql(info);
          ? }
          }
          就是在實(shí)時(shí)檢測(cè)channel中的產(chǎn)品。
          channel是一個(gè)阻塞通道BlockedChannel的實(shí)例,這個(gè)阻塞通道主要提供兩個(gè)方法offer,take,offer方法向通道中放入產(chǎn)品,take從通道中取產(chǎn)品,當(dāng)通道中沒有產(chǎn)品的時(shí)候,take方法將會(huì)阻塞,直到有產(chǎn)品為止。BlockedChannel是靠java的wait-notify機(jī)制實(shí)現(xiàn)的,原理非常簡(jiǎn)單,有興趣的朋友看一下其實(shí)現(xiàn)代碼就可以。
          值得注意的是,LogConsumer是一個(gè)后臺(tái)線程,因?yàn)槿绻鸏ogConsumer不是后臺(tái)線程,那么由于LogConsumer一直在無限循環(huán)里執(zhí)行,所以程序就不能正常終止。而設(shè)置為后臺(tái)線程后,在其他工作線程停止后,此線程就會(huì)自動(dòng)終止。關(guān)于“后臺(tái)線程”的知識(shí),可以查看相關(guān)資料。
          但是采用后臺(tái)線程以后,又有另一個(gè)問題出現(xiàn)了,在主線程停止后,有可能產(chǎn)品通道channel中還有沒有發(fā)送完的日志信息,這樣就會(huì)造成漏記日志信息。
          Runtime 類有一個(gè)addShutDownHook方法,可以調(diào)用此方法向JVM注冊(cè)一個(gè)監(jiān)聽器,這個(gè)監(jiān)聽器必須實(shí)現(xiàn)Thread接口,在JVM停止之前,這個(gè)監(jiān)聽器將會(huì)被運(yùn)行,這樣我們就可以在JVM停止之前做一些事情了。
          JDBMonitor就是用addShutDownHook解決此問題的。見DBLogger的靜態(tài)初始化塊:

          Runtime.getRuntime().addShutdownHook(new Thread(){
          ? public void run()
          ? {
          ??? //once JVM will shutDown,this hook will pause the shutingdown
          ??? //until all the SQLInfo be dispatched
          ??? while (!channel.isEmpty())
          ??? {
          ????? try
          ????? {
          ??????? Thread.sleep(SHUTDOWNSLEEPMSECOND);
          ????? } catch (Exception e)
          ????? {
          ??????? throw CommonUtils.toRuntimeException(e);
          ????? }
          ??? }
          ??? ...
          ?? }
          });?

          在JVM停止之前會(huì)首先檢測(cè)產(chǎn)品通道中有沒有產(chǎn)品,如果還有,則會(huì)一直等到產(chǎn)品被消費(fèi)完后再終止。

          ?while (!channel.isEmpty())
          ??? {
          ????? try
          ????? {
          ??????? Thread.sleep(SHUTDOWNSLEEPMSECOND);
          ????? } catch (Exception e)
          ????? {
          ??????? throw CommonUtils.toRuntimeException(e);
          ????? }
          ??? }

          posted on 2006-06-02 23:46 CowNew開源團(tuán)隊(duì) 閱讀(944) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 兴山县| 贵溪市| 南雄市| 城固县| 阳东县| 永春县| 石渠县| 甘洛县| 石楼县| 容城县| 乌拉特中旗| 乐平市| 马关县| 台中市| 莱阳市| 太仓市| 沾化县| 鹤峰县| 翁源县| 招远市| 定远县| 安陆市| 修水县| 维西| 新源县| 富民县| 新密市| 临猗县| 定日县| 平阳县| 富宁县| 五寨县| 定南县| 黄陵县| 牙克石市| 大英县| 曲麻莱县| 南安市| 云浮市| 广汉市| 道孚县|