Java设计模式——观察者模式的灵活应用
灵感来源于一个猪队友给我的题目

看到这个,我抓住的关键字是:任何子任务失败,要通知所有子任务执行取消逻辑。
这不就是消息广播吗?观察者模式!
干活
首先是收听者
package com.example.broadcast; /**
* 每个节点即是广播者,也是收听者
*/
public interface Listener { /**
* 设置调度中心
*/
void setCenter(DispatchCenter center); /**
* 主动通知其它收听者
*/
void notice(String msg); /**
* 自己收到通知的处理逻辑
* @param msg
*/
void whenReceived(String msg); /**
* 收听者标志:唯一
* @return
*/
String identify(); }
然后是调度中心
package com.example.broadcast; /**
* 调度中心
*/
public interface DispatchCenter { /**
* 广播
* @param own 广播的时候,要排除自己
* @param msg 广播消息
*/
void broadcast(String own, String msg); /**
* 添加收听者
* @param listener
*/
void addListener(Listener listener); }
调度中心实现
package com.example.broadcast; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; public class DispatchCenterImpl implements DispatchCenter { private static final Map<String, Listener> MAP = new ConcurrentHashMap<>(); @Override
public void broadcast(String own, String msg) {
MAP.forEach((k,v) -> {
// 不用给自己发通知
if (!k.equals(own)){
v.whenReceived(msg);
}
});
} @Override
public void addListener(Listener listener) {
listener.setCenter(this);
MAP.put(listener.identify(), listener);
}
}
剩下三个收听者
package com.example.broadcast;
import java.util.UUID;
public class ListenerA implements Listener {
private DispatchCenter center;
private String identify;
public ListenerA() {
identify = UUID.randomUUID().toString();
}
@Override
public void setCenter(DispatchCenter center) {
this.center = center;
}
@Override
public void notice(String msg) {
center.broadcast(identify, msg);
}
@Override
public void whenReceived(String msg) {
System.out.println(this.getClass().getName() + "收到消息:" + msg);
}
@Override
public String identify() {
return identify;
}
}
B和C除了类名不一样,其他都一样,不再赘述。目录如下

测试
package com.example.broadcast; import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Main { public static void main(String[] args) {
DispatchCenter center = new DispatchCenterImpl();
ListenerA listenerA = new ListenerA();
ListenerB listenerB = new ListenerB();
ListenerC listenerC = new ListenerC();
center.addListener(listenerA);
center.addListener(listenerB);
center.addListener(listenerC); ExecutorService executorService = Executors.newFixedThreadPool(3); // A触发1条事件
executorService.submit(() -> {
int i = 1;
while (i > 0){
listenerA.notice(listenerA.getClass().getName() + "说:我有" + new Random().nextInt(1000000) + "元");
i--;
}
});
// B触发2条事件
executorService.submit(() -> {
int i = 2;
while (i > 0){
listenerB.notice(listenerB.getClass().getName() + "说:我有" + new Random().nextInt(1000000) + "元");
i--;
}
});
// C触发3条事件
executorService.submit(() -> {
int i = 3;
while (i > 0){
listenerC.notice(listenerC.getClass().getName() + "说:我有" + new Random().nextInt(1000000) + "元");
i--;
}
}); executorService.shutdown(); } }
输出:

流程图

当其中的B节点,发生了错误,除了把自己处理好之外
1. 向调度中心发送广播请求,并携带需要的消息
2. 调度中心遍历收听者,挨个通知(执行)每一个收听者接受消息的逻辑
关于停止任务
因为题目要求,【快速取消】所有子任务
关于线程停止的方法也有很多:
1. 优雅退出run方法
2. 暴力stop
3. run方法抛出异常
如果说要求,A异常了,B和C收到消息之后,线程立即停止,不能有一点迟疑,说实话我还没想到该怎么做。因为你要知道,实际上的任务的run方法内部,不太可能是个while循环,人家可能就是个顺序执行,所以停止标志位的方式,并不适用。
而其它的方法,我也没想到很好的。我只能写个按照标志位停止的“玩具”
修改三个收听者代码和测试类
package com.example.broadcast; import lombok.SneakyThrows; import java.util.Random;
import java.util.UUID; public class ListenerA implements Listener,Runnable { private DispatchCenter center;
private String identify; public ListenerA() {
identify = UUID.randomUUID().toString();
} @Override
public void setCenter(DispatchCenter center) {
this.center = center;
} @Override
public void notice(String msg) {
center.broadcast(identify, msg);
} @Override
public void whenReceived(String msg) {
System.out.println(this.getClass().getName() + "收到消息:" + msg);
} @Override
public String identify() {
return identify;
} @SneakyThrows
@Override
public void run() {
// 5秒之后,模拟发生异常
Thread.sleep(5000);
notice(this.getClass().getName() + "说:我有" + new Random().nextInt(1000000) + "元");
System.out.println(this.getClass().getName() + "程序异常,并已经传播了消息...");
}
}
package com.example.broadcast;
import lombok.SneakyThrows;
import java.util.UUID;
public class ListenerB implements Listener,Runnable {
private DispatchCenter center;
private String identify;
private volatile Boolean stopFlag = false;
public ListenerB() {
identify = UUID.randomUUID().toString();
}
@Override
public void setCenter(DispatchCenter center) {
this.center = center;
}
@Override
public void notice(String msg) {
center.broadcast(identify, msg);
}
@Override
public void whenReceived(String msg) {
System.out.println(this.getClass().getName() + "_" + Thread.currentThread().getName() + "收到消息:" + msg);
// 停止当前线程
stopFlag = true;
}
@Override
public String identify() {
return identify;
}
@SneakyThrows
@Override
public void run() {
while (!stopFlag){
Thread.sleep(1000);
System.out.println(this.getClass().getName() + "_" + Thread.currentThread().getName() + "__B在执行任务");
}
System.out.println(this.getClass().getName() + "_" + Thread.currentThread().getName() + "__B Dead");
}
}
package com.example.broadcast;
import lombok.SneakyThrows;
import java.util.UUID;
public class ListenerC implements Listener,Runnable {
private DispatchCenter center;
private String identify;
private volatile Boolean stopFlag = false;
public ListenerC() {
identify = UUID.randomUUID().toString();
}
@Override
public void setCenter(DispatchCenter center) {
this.center = center;
}
@Override
public void notice(String msg) {
center.broadcast(identify, msg);
}
@Override
public void whenReceived(String msg) {
System.out.println(this.getClass().getName() + "_" + Thread.currentThread().getName() + "收到消息:" + msg);
// 停止当前线程
stopFlag = true;
}
@Override
public String identify() {
return identify;
}
@SneakyThrows
@Override
public void run() {
while (!stopFlag){
Thread.sleep(1000);
System.out.println(this.getClass().getName() + "_" + Thread.currentThread().getName() + "__C在执行任务");
}
System.out.println(this.getClass().getName() + "_" + Thread.currentThread().getName() + "__C Dead");
}
}
测试
package com.example.broadcast; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Main { public static void main(String[] args) {
DispatchCenter center = new DispatchCenterImpl();
ListenerA listenerA = new ListenerA();
ListenerB listenerB = new ListenerB();
ListenerC listenerC = new ListenerC();
center.addListener(listenerA);
center.addListener(listenerB);
center.addListener(listenerC); ExecutorService executorService = Executors.newFixedThreadPool(3); // A
executorService.submit(listenerA);
// B
executorService.submit(listenerB);
// C
executorService.submit(listenerC); executorService.shutdown(); } }

这个是这么多年第一个发到首页的,就是想问下大家怎样解决这种情况下的线程停止问题
Java设计模式——观察者模式的灵活应用的更多相关文章
- java设计模式--观察者模式(Observer)
java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...
- 【设计模式】Java设计模式 - 观察者模式
[设计模式]Java设计模式 - 观察者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 @一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长 ...
- JAVA 设计模式 观察者模式
用途 观察者模式 (Observer) 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象. 这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 观 ...
- Java设计模式--观察者模式到监听器
观察者模式是对象的行为模式.又叫做发布-订阅模式.模型-视图模式.源-监听器模式. 抽象主题角色:主题角色将所有对观察者对象的引用到保存在一个集合里,每个主题都可以拥有任意数量的观察者.抽象主题提供一 ...
- Java设计模式の观察者模式(推拉模型)
目录: 一.观察者定义 二.观察者模式的结构(推模式实现) 三.推模型和拉模型(拉模式实现) 四.JAVA提供的对观察者模式的支持 五.使用JAVA对观察者模式的支持(自带推模式实现实例) 一.观察者 ...
- Java设计模式 - 观察者模式
定义 观察者模式属于对象行为型模式. 在对象之间定义一对多的依赖,这样一来当一个对象改变状态,依赖它的对象都会收到通知并自动更新. 优点 1. 主题和观察者之间抽象耦合.无论什么对象主要实现了特定的 ...
- 我的Java设计模式-观察者模式
相信大家都有看过<喜洋洋与灰太狼>,说的是灰太狼和羊族的"斗争",而每次的结果都是灰太狼一飞冲天,伴随着一句"我还会回来的......".为灰太狼感 ...
- java设计模式-观察者模式学习
最近学习了设计模式中的观察者模式,在这里记录下学习成果. 观察者模式,个人理解:就是一个一对多模型,一个主体做了事情,其余多个主体都可以观察到.只不过这个主体可以决定谁去观察他,以及做什么事情可以给别 ...
- Java设计模式——观察者模式(事件监听)
最近在看Tomcat和Spring的源码,在启动的时候注册了各种Listener,事件触发的时候就执行,这里就用到了设计模式中的观察者模式. 引-GUI中的事件监听 想想以前在学Java的GUI编程的 ...
随机推荐
- java实现单链表、栈、队列三种数据结构
一.单链表 1.在我们数据结构中,单链表非常重要.它里面的数据元素是以结点为单位,每个结点是由数据元素的数据和下一个结点的地址组成,在java集合框架里面 LinkedList.HashMap(数组加 ...
- viewpager欢迎页面底部点的滑动效果
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layo ...
- 走在深夜的小码农 Third Day
Css3 Third Day writer:late at night codepeasant css简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称. ...
- 浅谈分布式共识算法raft
前言:在分布式的系统中,存在很多的节点,节点之间如何进行协作运行.高效流转.主节点挂了怎么办.如何选主.各节点之间如何保持一致,这都是不可不面对的问题,此时raft算法应运而生,专门 用来解决上述问题 ...
- 专题五:redis的数据类型之set
一.基本简介 现在出现了新的查询需求:存储大量数据的同时,还需要在查询方面提供更高的效率.虽然list满足存储大量的数据,也可以通过索引来进行访问,但是list底层是双向链表的结构,在查询上的效率并没 ...
- Git远程推送常见错误及解决方案:
Git远程推送 关注公众号"轻松学编程"了解更多. 1.问题:git远程提交时出现错误: error: RPC failed; curl 56 OpenSSL SSL_read: ...
- 没人比我更懂 HashMap :)
哈,标题开个玩笑,0202 年的段子哈. 一.首先看一下 HashMap 的构造函数 /** * Constructs an empty <tt>HashMap</tt> wi ...
- leetcode95:jump game
题目描述 给出一个非负整数数组,你最初在数组第一个元素的位置 数组中的元素代表你在这个位置可以跳跃的最大长度 判断你是否能到达数组最后一个元素的位置 例如 A =[2,3,1,1,4], 返回 tru ...
- python爬虫06取当当网 Top 500 本五星好评书籍
主要思路 使用 page 变量来实现翻页 我们使用 requests 请求当当网 然后将返回的 HTML 进行正则解析 由于我们暂时还没学到数据库 所以解析完之后就把内容存到文件中 def main( ...
- C#设计模式-责任链模式(Chain of Responsibility Pattern)
引子 一个事件需要经过多个对象处理是一个挺常见的场景,譬如采购审批流程,请假流程,软件开发中的异常处理流程,web请求处理流程等各种各样的流程,可以考虑使用责任链模式来实现.现在以请假流程为例,一般公 ...