暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【经验与坑】Java观察者模式续

由上回书中所提及的只是一个简单的demo,没有充分考虑到实际的开发场景。在往实际项目中套的时候,发现还是有必要再深入一下。


Java观察者模式上

及萨博涵五六,公众号:码农智涵的程序人生【经验与坑】Java监控多线程,意外退出线程后自动重启Demo


在实际业务当中,启动线程的时候常常需要携带一些参数来初始化线程内部的工作。昨天并没有提到这一问题,而且仅仅使用了一个线程做测试并不严谨。这次将设置两个线程并加入线程重启带参的功能。


(1)添加一个参数实体类 ListenEntity.java

    package entity;


    public class ListenEntity {




    private String string;


    private String string2;


    public String getString() {
    return string;
    }


    public void setString(String string) {
    this.string = string;
    }


    public String getString2() {
    return string2;
    }


    public void setString2(String string2) {
    this.string2 = string2;
    }




    }


    每一次线程出现崩溃时就会在Catch中触发 doBusiness 方法,通过 doBusiness方法触发 Listener (观察者)中的 update 方法进行重启线程。

    (2)被观察者 RunTread.java

      //被观察者
      public class RunThread extends Observable implements Runnable{


      ListenEntity listenEntity = new ListenEntity();




      public void setListenEntity(ListenEntity listenEntity) {
      this.listenEntity = listenEntity;
      }


      //此方法一被调用,立马通知观察者,在本demo中是监听线程
      public void doBusiness(){
      if(true){
      super.setChanged();
      }


      notifyObservers(this.listenEntity);
      }


      @Override
      public void run() {
      // TODO Auto-generated method stub
      int c = 0;
      //模拟线程运行一段事件之后退出
      while(true){


      System.out.println("Running-"+c+" "+new Date());
      System.out.println(Thread.currentThread().getName()+"正在执行");


      try{
      System.out.println("线程睡眠2秒");
      Thread.sleep(2000);
      }catch(InterruptedException e){
      e.printStackTrace();
      doBusiness();
      break;
      }




      c++;


      //模拟抛出异常
      try{
      if(c==2){
      String str = null;
      str.length();//这里由于声明str为空,所以会报错(模拟线程异常崩溃)
      }
      }catch(Exception e){
      e.printStackTrace();
      doBusiness();//在抛出异常时调用,通过观察者,让其重启线程
      break;
      }

      }
      }

      public static void main(String[] args) {
      //声明第一个线程对象 并为其声明观察者对象 listener1
      ListenEntity listenEntity = new ListenEntity();
      listenEntity.setString("线程1携带参数1");
      listenEntity.setString2("线程1携带参数2");
      RunThread runThread1 = new RunThread();
      runThread1.setListenEntity(listenEntity);
      Listener listener1 = new Listener();
      runThread1.addObserver(listener1);

      //声明第二个线程对象 并声明第二个观察者对象 listener2
      ListenEntity listenEntity2 = new ListenEntity();
      listenEntity2.setString("线程2携带参数1");
      listenEntity2.setString2("线程2携带参数2");
      RunThread runThread2 = new RunThread();
      runThread2.setListenEntity(listenEntity2);
      Listener listener2 = new Listener();
      runThread2.addObserver(listener2);

      //启动多线程
      Thread thread1 = new Thread(runThread1,"线程1");
      Thread thread2 = new Thread(runThread2,"线程2");
      thread1.start();thread2.start();
      }


      }

      notifyObservers(this.listenEntity);

      可以看到,主要的变化的位置就在这个 notifyObservers方法的参数上,上次使用的只是它的初级版本没啥实际用处。但实际上它在设计时就给出了后续业务层面应用的余地。我们将出现猝死的线程复活所需要的参数通过 notify 大哥传给观察者的update方法,让观察者大夫赶快救救孩子。

      看一下源码:

            public void notifyObservers(Object arg) {
        /*
        * a temporary array buffer, used as a snapshot of the state of
        * current Observers.
        */
        Object[] arrLocal;


        synchronized (this) {
        /* We don't want the Observer doing callbacks into
        * arbitrary code while holding its own Monitor.
        * The code where we extract each Observable from
        * the Vector and store the state of the Observer
        * needs synchronization, but notifying observers
        * does not (should not). The worst result of any
        * potential race-condition here is that:
        * 1) a newly-added Observer will miss a
        * notification in progress
        * 2) a recently unregistered Observer will be
        * wrongly notified when it doesn't care
        */
        if (!changed)
        return;
        arrLocal = obs.toArray();
        clearChanged();
        }


        for (int i = arrLocal.length-1; i>=0; i--)
        ((Observer)arrLocal[i]).update(this, arg);
        }

        这里notifyObservers(Object obj)的参数对应的就是 update 方法的第二个参数。根据源码可以看出,一旦被观察者的状态改变了,观察者会在处理这个问题的时候上锁,对当前状态进行释放,然后进入for循环中对众多观察者的update方法一一调用。



        (3)观察者 Listener.java

          //观察者
          public class Listener implements Observer{


          @Override
          public void update(Observable arg0, Object object) {
          // TODO Auto-generated method stub
          ListenEntity listenEntity = (ListenEntity)object;
          System.out.println("线程死机");
          System.out.println("线程重启流程接收到的参数:"+listenEntity.getString());
          RunThread runThread = new RunThread();
          runThread.setListenEntity(listenEntity);
          runThread.addObserver(this);
          Thread thread = new Thread(runThread);
          thread.start();
          System.out.println("线程重启成功");
          }
          }


          最后看一下结合实际后的效果:


          文章转载自码农智涵的程序人生,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论