Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 295|回复: 0

[Java线程学习]Java实时多任务调度过程中的安全监控设计

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-29 23:58:11 | 显示全部楼层 |阅读模式
    在一系列关联的多任务的实时环境中,如果有一个任务发生失败,可能导致所有任务产生连锁反应,从而造成调度失控的局面。特别是对于核心控制设备尤其重要,为了解决这个问题,必须对每个任务进行实时监控。  
        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;  
      改变状态  
      
           整个监控就是围绕这些状态标志和行为展开的。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. 源代码:
    1. // 核心调度程序
    2. public class mythread {
    3.   public mythread() {  }
    4.   public static void main(String[] args) {
    5.     M m = new M();
    6.   }
    7. }
    8. // A 任务线程
    9. class A extends Thread {
    10.   public static boolean dead = false;
    11.   M m;
    12.   A(M m){
    13.     m = m;
    14.     start();
    15.   }
    16.   public void run(){
    17.      try{
    18.       for(int i=-3;i<= 5;i++){
    19.         int j=1/i;   // 人为设置过程中陷阱
    20.         dead = !dead;  // 活动状态
    21.         System.out.println("i=" + i + ": status=" + dead);
    22.         try{
    23.           sleep(2000);
    24.         }
    25.         catch(InterruptedException ie){
    26.           System.out.println("A is Interrupted!");
    27.         }
    28.       }
    29.       m.Keepchecking = false;  //A 正常结束后关闭监控线程
    30.       System.out.println("A is Ending M");
    31.     }
    32.     catch(Exception e){
    33.       System.out.println("A become Exception!");
    34.     }
    35.   }
    36. }
    37. // 监控线程
    38. class M extends Thread{
    39.   public static boolean Keepchecking = true;  // 持续监控标志
    40.   boolean laststatus;     //保存上次监控状态
    41.   int maydeadtimes = 0;  //监控线程可能死亡的计数器
    42.   int maydeadtimeout = 3;//定义判断线程死亡的边界条件
    43.   int deadtimes = 0;     //监控线程死亡次数的计数器
    44.   int deadtimeout = 3;   //定义判断线程不正常的边界条件
    45.   A a;
    46.   M(){start();}
    47.   public void run(){
    48.     schedule();
    49.     while(Keepchecking){
    50.       laststatus = a.dead;
    51.       try{
    52.         sleep(2000);
    53.       }
    54.       catch(InterruptedException e){
    55.         System.out.println("M is Interrupted!");
    56.       }
    57.       System.out.println("M read A status = " + a.dead);
    58.       if(laststatus == a.dead ){
    59.         if(++maydeadtimes >= maydeadtimeout){
    60.           if(++deadtimes >= deadtimeout){
    61.             System.out.println("Alert! A is unstable, M will stop it");
    62.             a = null;
    63.             break;
    64.           }
    65.           else{
    66.             System.out.println( "A is deaded!");
    67.             schedule();
    68.             System.out.println("M is restarting A!
    69. ____________________________
    70. ");
    71.           }
    72.         }
    73.       }
    74.       else{
    75.         maydeadtimes = 0;
    76.       }
    77.     }
    78.   }
    79.   private void schedule(){
    80.     A a = new A(this);
    81.   }
    82. }
    复制代码


      
      
       
       

         
       

         
       
      
       









    源码下载:http://file.javaxxz.com/2014/10/29/235811437.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 23:07 , Processed in 0.354881 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表