当前位置: 主页 > JAVA语言

状态模式 java-Java观察者模式上及萨博涵五六:线程重启带参

发布时间:2023-07-09 09:07   浏览次数:次   作者:佚名

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

Java观察者模式上

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

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

状态模式的优点_状态模式和策略模式的区别_状态模式 java

(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;
}




}


状态模式 java_状态模式和策略模式的区别_状态模式的优点

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

(2)被观察者 RunTread.java

状态模式的优点_状态模式和策略模式的区别_状态模式 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);

状态模式和策略模式的区别_状态模式 java_状态模式的优点

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

看一下源码:

状态模式 java_状态模式的优点_状态模式和策略模式的区别

    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 方法的第二个参数。根据源码可以看出状态模式 java,一旦被观察者的状态改变了,观察者会在处理这个问题的时候上锁,对当前状态进行释放,然后进入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("线程重启成功");
}
}

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