方浩波 (fanghb@eastcom.com)东方通信网络研究所

简介: 在一系列关联的多任务的实时环境中,如果有一个任务发生失败,可能导致所有任务产生连锁反应,从而造成调度失控的局面。特别是对于核心控制设备尤其重要,为了解决这个问题,必须对每个任务进行实时监控。

发布日期: 2002 年 12 月 29 日 
级别: 初级 
访问情况 : 4559 次浏览 
评论:  (查看 | 添加评论 -
登录)

 平均分 (7个评分)
为本文评分

在一系列关联的多任务的实时环境中,如果有一个任务发生失败,可能导致所有任务产生连锁反应,从而造成调度失控的局面。特别是对于核心控制设备尤其重要,为了解决这个问题,必须对每个任务进行实时监控。

问题分析

在JAVA环境中,一个任务一般是由一个独立线程来引导实现的,独立线程可能调用一系列子线程。如果在执行过程中,某一个线程发生异常(产生的原因很多,比如软件升级、运行环境改变、系统资抢占等),那么该线程就会停止运行,直到下次任务重新被提交。对于实时环境来说当前任务是失败的。我们无法预测和完全避免异常的发生,但是可以通过一些技术手段来跟踪任务的状态,从而及时发现问题并恢复正常,减少损失。

回页首

设计原理

对于一个实时任务而言,执行效率是非常关键的,这意味着不可能考虑用非常复杂的方式来实现任务监控,即使这样可以做的比较完善,同时监控代码本身也会引入一些异常,这就要求监控程序必须简单可靠,能够发现大多数问题,并能及时处理。

一个可能的简单实现。

我们对每个任务加上一个监控的"壳",调度程序调用这个"壳"来完成对具体任务的引导和监控,相当于每个任务具有自治能力。这样做的好处有:

  1. 分散控制。不需要修改调度主体程序,不增加调度过程的复杂度;
  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; 改变状态

整个监控就是围绕这些状态标志和行为展开的。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 

(结束) 

回页首

结束语

通过给制定任务线程增加监控线程,可以很好地解决实时多任务环境下的安全监控问题,同时避免了核心调度线程事务过分复杂的问题。实践证明,该方法复杂度小,占用资源少,运行可靠,适合复杂条件下的多任务环境。

回页首

源代码:

package safethread;
// 核心调度程序
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);
}
}

关于作者

方浩波 在位于中国浙江杭州市的东方通信股份公司网络研究所工作。目前,他从事移动通信网络管理软件的设计和测试工作。在此之前,他主要负责多媒体视频会议产品的开发和技术推广,此外还从事过无线通信产品电路设计和交换机软件的研发。您可以通过fanghb@eastcom.com
方浩波 联系。

Java实时多任务调度过程中的安全监控设计的更多相关文章

  1. GoEasy实现web实时推送过程中的自动补发功能

    熟悉GoEasy推送的朋友都知道GoEasy推送实现web实时推送并且能够非常准确稳定地将信息推送到客户端.在后台功能中查看接收信息详情时,可有谁注意到有时候在发送记录里有一个红色的R标志?R又代表的 ...

  2. Java连接远程Mysql过程中遇到的各种问题

    2018-11-16 10:46 2018-11-19 21:35 前言 本篇文章记录的是本人在使用Java程序连接另一台电脑(同一局域网)上的Mysql数据库的过程中遇到的各种问题及解决方案.希望能 ...

  3. cmd窗口中java命令报错。错误:找不到或无法加载主类 java的jdk安装过程中踩过的坑

    错误: 找不到或无法加载主类 HelloWorld 遇到这个问题时,我尝试过网上其他人的做法.有试过添加classpath,也有试过删除classpath.但是依然报错,这里javac可以编译通过,说 ...

  4. java new一个对象的过程中发生了什么

    java在new一个对象的时候,会先查看对象所属的类有没有被加载到内存,如果没有的话,就会先通过类的全限定名来加载.加载并初始化类完成后,再进行对象的创建工作. 我们先假设是第一次使用该类,这样的话n ...

  5. (转)Java new一个对象的过程中发生了什么

    Java在new一个对象的时候,会先查看对象所属的类有没有被加载到内存,如果没有的话,就会先通过类的全限定名(包名+类名)来加载.加载并初始化类完成后,再进行对象的创建工作. 我们先假设是第一次使用该 ...

  6. java new一个对象的过程中发生了什么?

    java在new一个对象的时候,会先查看对象所属的类有没有被加载到内存,如果没有的话,就会先通过类的全限定名来加载.加载并初始化类完成后,再进行对象的创建工作. 我们先假设是第一次使用该类,这样的话n ...

  7. Java同步和异步过程中消息语言国际化处理策略

    在Java后端做消息内容的语言国际化处理时可以通过Spring中MessageSource接口的来实现,但是MessageSource接口需要用到Locale对象, 而Locale类又是根据前端传过来 ...

  8. Java面试题系列(三)Java new一个对象的过程中发生了什么

    Person class Person{ private String name; private int age; public Person() { super(); } public Perso ...

  9. java基础:多态过程中的动态绑定

    重刷java-core的chapter05,P158 重读多态,感觉又不一样了. 记录一下对象方法执行过程: 1.  编译器查看对象声明类型和方法名,如class.fuction(param),cla ...

  10. Java调用Oracle存储过程过程中几个问题

    1.java.sql.SQLException: 无效的名称模式: STKSETTLEADMIN.TY_MARKETDATA 用户STKSETTLEADMIN下没有TY_MARKETDATA,类型TY ...

随机推荐

  1. .net 环境使用 RabbitMQ ,由浅入深 【一】

    最近因为先开发的项目需要用到消息队列,因此捣鼓了一下市面上开源的消息队列. 原本听闻Rocketmq ,一开始用的是 RocketMQ,各种集群搭建完毕,消息发送什么的测试后,,但是结果因为 Rock ...

  2. Coursera Self-driving1, introduction

    有哪些 Sensors? 摄像头和激光雷达,毫米波雷达等 sensor 分类: exteroceptive (surrounding), 有 camera(Resolution, FOV, Dynam ...

  3. IntelliJ Idea 常用快捷键参照列表

    IntelliJ Idea 常用快捷键参照列表 Ctrl+Shift + Enter,语句完成 "!",否定完成,输入表达式时按 "!"键 Ctrl+E,最近的 ...

  4. mongo查看服务状态

    转载请注明出处: 查看数据库列表 show dbs 查看当前数据库 db 查看集合列表 show collections 查看数据库的状态 db.stats() 查看集合的状态 db.collecti ...

  5. word在原有的方框里打勾

    按住键盘上的ALT键不放,然后在小键盘区输入"9745"这几个数字,最后松开 ALT 键,自动变成框框中带勾符号.

  6. 《HelloGitHub》第 102 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. github.com/521xueweihan/HelloG ...

  7. AD域下,没有登录服务器处理登录请求

    原因: IP地址配置有问题 或者 DNS : 解决办法: 重新设置 IP地址 和 DNS : 此案例中, 切换到 test 账户(域管理员)后发现 , 未配置 IP地址 和 DNS :

  8. 00 你想要学习的 AI+Python,捷径在这里

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  9. Android复习(三)清单文件中的元素——>uses-feature

    <uses-feature> Google Play 会利用应用清单中声明的 <uses-feature> 元素,从不符合应用硬件和软件功能要求的设备上过滤该应用. 通过指定应 ...

  10. HDU-ACM 2024 Day1

    T1009 数位的关系(HDU 7441) 考虑 \(l = r\) 的情况,此时只要计算一个数字,我们将其展开为一个字符串 \(S\).设 \(f_{i, j, k}\) 表示考虑了 \(S\) 的 ...