1. 问题分析
在JAVA环境中,一个任务一般是由一个独立线程来引导实现的,独立线程可能调用一系列子线程。如果在执行过程中,某一个线程发生异常(产生的原因很多,比如软件升级、运行环境改变、系统资抢占等),那么该线程就会停止运行,直到下次任务重新被提交。对于实时环境来说当前任务是失败的。我们无法预测和完全避免异常的发生,但是可以通过一些技术手段来跟踪任务的状态,从而及时发现问题并恢复正常,减少损失。
2. 设计原理
对于一个实时任务而言,执行效率是非常关键的,这意味着不可能考虑用非常复杂的方式来实现任务监控,即使这样可以做的比较完善,同时监控代码本身也会引入一些异常,这就要求监控程序必须简单可靠,能够发现大多数问题,并能及时处理。
一个可能的简单实现。
我们对每个任务加上一个监控的"壳",调度程序调用这个"壳"来完成对具体任务的引导和监控,相当于每个任务具有自治能力。这样做的好处有:
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; | 改变状态 |
[1] [2] [3] 下一页