状态模式 java-Java观察者模式上及萨博涵五六:线程重启带参
发布时间:2023-07-09 09:07 浏览次数:次 作者:佚名
由上回书中所提及的只是一个简单的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);
可以看到状态模式 java,主要的变化的位置就在这个 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 方法的第二个参数。根据源码可以看出状态模式 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("线程重启成功");
}
}
最后看一下结合实际后的效果: