eroself

          關于人生的程式,在這里譜寫......
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理

          Java實時多任務調度過程中的安全監控設計

          Posted on 2007-12-28 15:38 鬼谷子 閱讀(225) 評論(0)  編輯  收藏 所屬分類: Java
                  http://java.chinaitlab.com/model/528568.html

                  在一系列關聯的多任務的實時環境中,如果有一個任務發生失敗,可能導致所有任務產生連鎖反應,從而造成調度失控的局面。特別是對于核心控制設備尤其重要,為了解決這個問題,必須對每個任務進行實時監控。

                1. 問題分析

                在JAVA環境中,一個任務一般是由一個獨立線程來引導實現的,獨立線程可能調用一系列子線程。如果在執行過程中,某一個線程發生異常(產生的原因很多,比如軟件升級、運行環境改變、系統資搶占等),那么該線程就會停止運行,直到下次任務重新被提交。對于實時環境來說當前任務是失敗的。我們無法預測和完全避免異常的發生,但是可以通過一些技術手段來跟蹤任務的狀態,從而及時發現問題并恢復正常,減少損失。

            2. 設計原理

                對于一個實時任務而言,執行效率是非常關鍵的,這意味著不可能考慮用非常復雜的方式來實現任務監控,即使這樣可以做的比較完善,同時監控代碼本身也會引入一些異常,這就要求監控程序必須簡單可靠,能夠發現大多數問題,并能及時處理。

          一個可能的簡單實現。

                我們對每個任務加上一個監控的"殼",調度程序調用這個"殼"來完成對具體任務的引導和監控,相當于每個任務具有自治能力。這樣做的好處有:

          1. 分散控制。不需要修改調度主體程序,不增加調度過程的復雜度;
          2. 控制靈活,安全性高。對于不同任務可定義不同控制方式和控制參數,封裝在任務內部,靈活性好,對個別任務控制代碼的修改不會影響其他任務,即任務控制實現松藕合,避免錯誤擴散。適合團隊開發;
          3. 維護簡單,升級方便。對于新的任務加入也無需改變原來調度程序的結構,只需修改任務表及相關參數,這樣在性能提高的同時也簡化了軟件升級過程中的代碼維護量。


                 3. 設計實現

                 每個線程理論上有四種狀態:

          new 線程對象已經創建,但尚未啟動,不可運行
          runnable 一旦有時間分片機制有空閑的CPU周期,線程立即開始運行
          dead 從run()方法退出后,一個線程即消亡
          blocked 線程可運行,但有某種東西阻礙了它。調度機制不給它分配任何CPU時間,直到它進入runnable狀態

          在實際操作中,為了便于描述,我們重新規定了線程的狀態:

          Actived 線程已被激活,處于運行狀態
          Sleeping 線程完成一個特定任務后退出,進入休眠狀態
          Dead 線程運行過程中發生異常,終止運行,處于死亡狀態

          根據上述理論,我們只需要對Actived狀態的線程進行監控,也只有對Actived狀態監控才有意義,這是對監控模塊做出邏輯簡化。那么如何實現監控模塊對具體任務的監控呢?

          對具體任務的監控方式有多種,根據任務的不同,需要采用不同的監控代碼,但是在結構上基本相同。這和類的重載概念有點相似。本文附有一個簡單的例子。

          A任務每秒執行一個簡單的代數運算 j = 1/ i,并打印結果。我們故意在其中設置了一個異常陷阱,使得執行過程中出現一次被0除的算術異常,下面結合這個例子講述監控原理。

          為了監控A,我們設計了一個監控線程M。M中定義了一些關鍵邏輯變量:

          Keepchecking 持續監控標志
          laststatus 保存上次監控狀態
          maydeadtimes 監控線程可能死亡的計數器
          maydeadtimeout 定義判斷線程死亡的邊界條件
          deadtimes 監控線程死亡次數的計數器
          deadtimeout 定義判斷線程不正常的邊界條件

          為了適應監控,在A任務中相應增加一些可以被監控的狀態和行為:

          dead 死狀態標志
          dead = !dead; 改變狀態

          整個監控就是圍繞這些狀態標志和行為展開的。A任務定期修改自己的dead標志,dead是一個布爾變量,理論上只要A沒有死,那么dead肯定是周期變化的(和心跳概念差不多),M需要做的就是監控dead的變化。為了避免一些偶然因素導致的誤判,我們在M中設置了一些計數器和邊界值(maydeadtimes和maydeadtimeout),當M發現A的可能死亡次數超過一定限制后,判斷A已死亡,不在繼續等待了,作為實時處理,首先注銷A的實例,然后重新啟動A(和我們計算機死機的復位很像),然后進入新一輪監控。

                如果是因為系統偶然因素導致A死亡,那么在隨后的新的任務啟動過程中一般可以順利完成。但是萬一由于環境參數改變或軟件升級存在版本缺陷,A可能始終會產生異常,那么M是否需要耐心地監控下去呢?一個形象的例子是:如果你連續3次開機都失敗,你是否會懷疑機器有問題?當然,你會,那么M也應該會。

                為了對A任務重復多次死亡有一個統計,M中又引入了另外對計數器和邊界值(deadtimes和deadtimeout),和你開計算機的過程一樣,如果連續n次都發現A有問題,可以基本肯定不是由于偶然因素引起的,需要對A的代碼或系統的環境進行檢查。M會發出告警,通知必須要對A進行審查了,然后清空A,自己自動安全退出。如果在核心調度程序中設置一個標志接受M們的告警,就可以有足夠理由終止其他任務的執行。可以看見,在A任務發生異常期間,M承擔了核心調度程序的維護功能。特別是當任務數量比較多的情況,核心調度程序只能采用排隊方式處理任務異常,而且由于處理異常的復雜程度不同,無法保證對多任務異常的實時處理。

                還要考慮正常情況下A和M的關系。核心調度程序通過M啟動A任務后,M處于持續監控狀態,當A正常結束任務后,A需要通知M結束監控,這樣,當A進入休眠狀態后,M也不會占用內存空間,提高了系統資源的利用率。

                通過以上描述,可以看到,上述監控思想具有清晰的概念和可操作性,占用資源少,為保證系統連續穩定運行創造了條件。

          具體代碼實現附后。

          運行結果如下:

          異常情況 正常情況
          i=-3: status=true
          M read A status = true
          i=-2: status=false
          M read A status = false
          i=-1: status=true
          M read A status = true
          A become Exception!
          M read A status = true
          M read A status = true
          M read A status = true
          A is deaded!
          M is restarting A!
          ____________________________
          i=-3: status=false
          M read A status = false
          i=-2: status=true
          M read A status = true
          i=-1: status=false
          M read A status = false
          A become Exception!
          M read A status = false
          M read A status = false
          M read A status = false
          A is deaded!
          M is restarting A!
          ____________________________
          i=-3: status=true
          M read A status = true
          i=-2: status=false
          M read A status = false
          i=-1: status=true
          M read A status = true
          A become Exception!
          M read A status = true
          M read A status = true
          M read A status = true
          Alert! A is unstable, M will stop it
          (結束)
          i=1: status=true
          M read A status = true
          i=2: status=false
          M read A status = false
          i=3: status=true
          M read A status = true
          i=4: status=false
          M read A status = false
          i=5: status=true
          M read A status = true
          A is Ending M
          M read A status = true
          (結束)

                4. 結束語

                通過給制定任務線程增加監控線程,可以很好地解決實時多任務環境下的安全監控問題,同時避免了核心調度線程事務過分復雜的問題。實踐證明,該方法復雜度小,占用資源少,運行可靠,適合復雜條件下的多任務環境。


                5. 源代碼:

          // 核心調度程序
          public class mythread {
          public mythread() {  }
          public static void main(String[] args) {
          M m = new M();
          }
          }
          // A 任務線程
          class A extends Thread {
          public static boolean dead = false;
          M m;
          A(M m){
          m = m;
          start();
          }
          public void run(){
          try{
          for(int i=-3;i<= 5;i++){
          int j=1/i;   // 人為設置過程中陷阱
          dead = !dead;  // 活動狀態
          System.out.println("i=" + i + ": status=" + dead);
          try{
          sleep(2000);
          }
          catch(InterruptedException ie){
          System.out.println("A is Interrupted!");
          }
          }
          m.Keepchecking = false;  //A 正常結束后關閉監控線程
          System.out.println("A is Ending M");
          }
          catch(Exception e){
          System.out.println("A become Exception!");
          }
          }
          }
          // 監控線程
          class M extends Thread{
          public static boolean Keepchecking = true;  // 持續監控標志
          boolean laststatus;     //保存上次監控狀態
          int maydeadtimes = 0;  //監控線程可能死亡的計數器
          int maydeadtimeout = 3;//定義判斷線程死亡的邊界條件
          int deadtimes = 0;     //監控線程死亡次數的計數器
          int deadtimeout = 3;   //定義判斷線程不正常的邊界條件
          A a;
          M(){start();}
          public void run(){
          schedule();
          while(Keepchecking){
          laststatus = a.dead;
          try{
          sleep(2000);
          }
          catch(InterruptedException e){
          System.out.println("M is Interrupted!");
          }
          System.out.println("M read A status = " + a.dead);
          if(laststatus == a.dead ){
          if(++maydeadtimes >= maydeadtimeout){
          if(++deadtimes >= deadtimeout){
          System.out.println("Alert! A is unstable, M will stop it");
          a = null;
          break;
          }
          else{
          System.out.println( "A is deaded!");
          schedule();
          System.out.println("M is restarting A!\n____________________________\n");
          }
          }
          }
          else{
          maydeadtimes = 0;
          }
          }
          }
          private void schedule(){
          A a = new A(this);
          }
          }
          

          主站蜘蛛池模板: 两当县| 淳化县| 长顺县| 尼玛县| 茶陵县| 乌什县| 合山市| 环江| 寿宁县| 富民县| 祥云县| 灵璧县| 常宁市| 莎车县| 石河子市| 丽水市| 汤原县| 漳州市| 明光市| 无锡市| 青田县| 台南市| 泾阳县| 株洲县| 高碑店市| 嘉定区| 曲麻莱县| 简阳市| 安新县| 昭平县| 桦川县| 汶川县| 嫩江县| 固始县| 泸西县| 黎城县| 响水县| 松江区| 大田县| 沂南县| 广宁县|