在一系列關聯的多任務的實時環境中
如果有一個任務發生失敗
可能導致所有任務產生連鎖反應
從而造成調度失控的局面
特別是對於核心控制設備尤其重要
為了解決這個問題
必須對每個任務進行實時監控
問題分析
在JAVA環境中一個任務一般是由一個獨立線程來引導實現的獨立線程可能調用一系列子線程如果在執行過程中某一個線程發生異常(產生的原因很多比如軟件升級運行環境改變系統資搶占等)那麼該線程就會停止運行直到下次任務重新被提交對於實時環境來說當前任務是失敗的我們無法預測和完全避免異常的發生但是可以通過一些技術手段來跟蹤任務的狀態從而及時發現問題並恢復正常減少損失
設計原理
對於一個實時任務而言執行效率是非常關鍵的這意味著不可能考慮用非常復雜的方式來實現任務監控即使這樣可以做的比較完善同時監控代碼本身也會引入一些異常這就要求監控程序必須簡單可靠能夠發現大多數問題並能及時處理
一個可能的簡單實現
我們對每個任務加上一個監控的殼調度程序調用這個殼來完成對具體任務的引導和監控相當於每個任務具有自治能力這樣做的好處有
分散控制不需要修改調度主體程序不增加調度過程的復雜度
控制靈活安全性高對於不同任務可定義不同控制方式和控制參數封裝在任務內部靈活性好對個別任務控制代碼的修改不會影響其他任務即任務控制實現松藕合避免錯誤擴散適合團隊開發
維護簡單升級方便對於新的任務加入也無需改變原來調度程序的結構只需修改任務表及相關參數這樣在性能提高的同時也簡化了軟件升級過程中的代碼維護量
設計實現
每個線程理論上有四種狀態
new
線程對象已經創建
但尚未啟動
不可運行
runnable
一旦有時間分片機制有空閒的CPU周期
線程立即開始運行
dead
從run()方法退出後
一個線程即消亡
blocked
線程可運行
但有某種東西阻礙了它
調度機制不給它分配任何CPU時間
直到它進入runnable狀態
在實際操作中為了便於描述我們重新規定了線程的狀態
Actived
線程已被激活
處於運行狀態
Sleeping
線程完成一個特定任務後退出
進入休眠狀態
Dead
線程運行過程中發生異常
終止運行
處於死亡狀態
根據上述理論我們只需要對Actived狀態的線程進行監控也只有對Actived狀態監控才有意義這是對監控模塊做出邏輯簡化那麼如何實現監控模塊對具體任務的監控呢?
對具體任務的監控方式有多種根據任務的不同需要采用不同的監控代碼但是在結構上基本相同這和類的重載概念有點相似本文附有一個簡單的例子
A任務每秒執行一個簡單的代數運算 j = / i並打印結果我們故意在其中設置了一個異常陷阱使得執行過程中出現一次被除的算術異常下面結合這個例子講述監控原理
為了監控A我們設計了一個監控線程MM中定義了一些關鍵邏輯變量
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是否需要耐心地監控下去呢?一個形象的例子是如果你連續次開機都失敗你是否會懷疑機器有問題?當然你會那麼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=: status=true
M read A status = true
i=: status=false
M read A status = false
i=: 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=: status=false
M read A status = false
i=: status=true
M read A status = true
i=: 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=: status=true
M read A status = true
i=: status=false
M read A status = false
i=: 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=: status=true
M read A status = true
i=: status=false
M read A status = false
i=: status=true
M read A status = true
i=: status=false
M read A status = false
i=: status=true
M read A status = true
A is Ending M
M read A status = true
(結束)
結束語
通過給制定任務線程增加監控線程可以很好地解決實時多任務環境下的安全監控問題同時避免了核心調度線程事務過分復雜的問題實踐證明該方法復雜度小占用資源少運行可靠適合復雜條件下的多任務環境
源代碼
// 核心調度程序
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=;i<= ;i++){
int j=/i; // 人為設置過程中陷阱
dead = !dead; // 活動狀態
Systemoutprintln(i= + i + : status= + dead);
try{
sleep();
}
catch(InterruptedException ie){
Systemoutprintln(A is Interrupted!);
}
}
mKeepchecking = false; //A 正常結束後關閉監控線程
Systemoutprintln(A is Ending M);
}
catch(Exception e){
Systemoutprintln(A become Exception!);
}
}
}
// 監控線程
class M extends Thread{
public static boolean Keepchecking = true; // 持續監控標志
boolean laststatus; //保存上次監控狀態
int maydeadtimes = ; //監控線程可能死亡的計數器
int maydeadtimeout = ;//定義判斷線程死亡的邊界條件
int deadtimes = ; //監控線程死亡次數的計數器
int deadtimeout = ; //定義判斷線程不正常的邊界條件
A a;
M(){start();}
public void run(){
schedule();
while(Keepchecking){
laststatus = adead;
try{
sleep();
}
catch(InterruptedException e){
Systemoutprintln(M is Interrupted!);
}
Systemoutprintln(M read A status = + adead);
if(laststatus == adead ){
if(++maydeadtimes >= maydeadtimeout){
if(++deadtimes >= deadtimeout){
Systemoutprintln(Alert! A is unstable M will stop it);
a = null;
break;
}
else{
Systemoutprintln( A is deaded!);
schedule();
Systemoutprintln(M is restarting A!\n____________________________\n);
}
}
}
else{
maydeadtimes = ;
}
}
}
private void schedule(){
A a = new A(this);
}
}
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27589.html