前几天组里接到一个以前开发的已上线项目的维护任务,要求把其中的一些数据定时通过webservice接口上传到当地某市某平台上面,基本上算是个体力活儿了。
时间仓促只好加班加点,搜集比对 -->拼写SQL-->调试接口-->测试上传。。。
正要把十几个接口搞定的时候,突然接到新要求,还得把各个接口本次上传更新进行统一的统计和分析。于是哥儿几个就开始郁闷了,因为每个接口上传数据的单位时间比较慢,所以为了平均分配时间,我们定下每个接口都启用一个新线程去应对,因为实时性,所以没有搞什么临时表。
可能现在加上我的描述会很自然的联想到“观察者”上,但是当时突然接到新要求思维麻木感情烦躁下肯定不会那么快意识到。于是吃完晚饭(加班)组里还是没研究出啥好的方案,越研究越偏离正轨。
这时候我可爱的老婆知道我加班特意过来视察视察我,结果组里这群无耻的单身汉丢下工作直接围着我老婆嫂子长嫂子短的(我了个擦,这几个贱人居然开始给我打各种小报告),最后我老婆说去买东西问他们需要顺便带什么,我老婆一边问一边记 —— 这个时候我突然想到了什么 —— 最后我老婆说了一遍各人要带的东西然后大喊一声都OK了否?然后就出去买东西了。
等我老婆一出门,我想着我老婆那句“都OK了否?”突然灵光闪耀了~~这个TMD不就是“观察者”吗?!每个人(线程)向我老婆注册自己,然后每个人说出要带的东西(线程运行结束)后告诉我老婆(主题线程),我老婆(主题)接受他们(线程)通知,最后对比~~
哈哈,于是我说出了我的方案,组里的人目瞪口呆,单身汉们都郁闷了 —— 原来老婆的作用这么大!
写个例子代码,这里只简单的描述出统计对象(主题接口/主题实现):
/**
* 统计句柄 (主题接口)
* 给各个上传业务类持有
*
* 没有“向主题注册”的方法,因为在此不是必须
*/
public interface StatHandler {
// 通知统计线程,并将自己初次的统计数据传给统计线程
void notice(Map<String, Object> dataMap);
}
可以发现这个统计句柄(主题)没有传统观察者模式中的注册方法,因为这里不是很有必要,我只是需要知道是不是所有上传线程都结束了就行。
/**
* 统计的真正实现对象
* 也就是观察者模式中的 主题对象
*
*/
public class StatThread implements StatHandler, Runnable {
// 联调业务总数
private int regCount;
// 保存统计信息的map
private Map<String, Object> statMap =new HashMap<String, Object>();
// 创建统计对象时直接将联调总数记录
public StatThread(int regCount) {
this.regCount =regCount;
}
@Override
public void notice(Map<String, Object> dataMap) {
synchronized (statMap) {
// 此处省略 ... 对dataMap进行合并统计到statMap操作
// 若联调线程全部执行完毕
if ((--regCount) == 0) {
// 获取统计对象的锁,唤醒统计对象进行最后的统计输出
synchronized (this) {
this.notify();
}
}
}
}
@Override
public void run() {
synchronized (this) {
try {
// 启动及等待,并释放自己的锁
this.wait();
} catch (InterruptedException e) {
// 省略日志 ...
throw new RuntimeException();
}
}
// 省略统计结果的后期处理 ...
// ....
}
}