Guarded-Suspension模式
Guarded-Suspension模式,即保护性暂停模式,在生活中是很常见的哟。比如说我们在买奶茶后等待取餐、点外卖后等待取餐。这些生活例子都有一个特征,就是需要等待另外一个人搞定后,我们才可以行动。而我们今天介绍的这个设计模式,就是等我准备好你再行动的想法哦。那么跟着我往下学习这个模式吧。
解释图
旁边的解释图Thread,即处理线程,在我们下面的例子中就是外卖小哥,我。而这个GuardedObject被保护对象即一个受检查的目标,比如说我要看外卖到没,就去检查手机看外卖小哥给我发信息没,而有信息我就去拿外卖,没则不拿。这个手机即是受检查目标。
学习场景
我们以一个场景来学习这个设计模式,就拿我们点外卖,等待外卖小哥送到,再去拿外卖这个场景。那我们开始进行设计吧。发挥我们想象力,这场景就有我,外卖小哥,和我们联系的手机。而对应到程序中,我和外卖小哥其实都是处理线程。
//手机
Phone phone = new Phone();
//我
Consumer me = new Consumer("我",phone);
//外卖小哥
Deliver deliver = new Deliver("外卖小哥",phone);
既然这样,我们就先去设计手机吧。手机里既然可以看信息,那我们可以先设计个信息。
@Getter
@ToString
public class Message {
//信息内容
private final String content;
public Message(String content) {
this.content = content;
}
}
而我们有了信息,可以去设计一下手机。手机里有两个方法,一个发送短讯,一个是查看短讯。在这个例子中,我们是得等外卖小哥再去行动,否则要等待。对于外卖小哥,他是发送短讯的。我们则是查看短讯。
//GuardedObject
public class Phone {
//受检查目标
volatile Message message;
public synchronized void sendMes(Message message){
//设置短讯
this.message = new Message("您好,你的外卖已到,请取餐");
//唤醒别的线程行动
notifyAll();
}
public synchronized Message getMes(){
//辅助删除信息的
Message msg ;
while (this.message == null){
try {
System.out.println(Thread.currentThread().getName()+":咋害没给我发消息呢!");
//条件不成立则进行阻塞,也即外卖小哥没送到,就要进入阻塞。
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
msg = this.message;
//删除条件
this.message = null;
return msg;
}
}
我们设计完手机后,则设计下外卖小哥,外卖小哥是处理线程,他有发送短信取外卖的功能哟。
public class Deliver extends Thread {
//咋外卖小哥是否得要个手机哈哈
private final Phone phone;
public Deliver(String name, Phone phone) {
super(name);
this.phone = phone;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"正在赶往商家取餐..."+new Date(System.currentTimeMillis()).toString());
//模拟取餐消耗时间
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName()+"取餐成功,正在奔向你"+new Date(System.currentTimeMillis()).toString());
//模拟奔向你消耗时间
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"你的外卖距离你还有10m,注意取餐哟");
//到了发简讯通知你来拿外卖哟
phone.sendMes(new Message("你的外卖到了"));
}
}
接下来就是设计我辣。
public class Consumer extends Thread {
private final Phone phone;
public Consumer(String name, Phone phone) {
super(name);
this.phone = phone;
}
@Override
public void run() {
check();
}
private void check() {
System.out.println(Thread.currentThread().getName() + ":好饿啊,好想吃饭啊");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟查看短信,如果外卖小哥没送到,则会一直等。
Message mes = phone.getMes();
if (mes != null) {
System.out.println(Thread.currentThread().getName() + ":终于来了他妈到了" + new Date(System.currentTimeMillis()).toString());
System.out.println(Thread.currentThread().getName() + ":吃外卖" + mes.toString());
}
}
}
哈哈,完成上面的例子,我们开始测试下。
Phone phone = new Phone();
Consumer me = new Consumer("我",phone);
System.out.println("开始点餐"+new Date(System.currentTimeMillis()));
me.start();
//模拟点餐消耗的时间
Thread.sleep(20000);
Deliver deliver = new Deliver("外卖小哥",phone);
deliver.start();
me.join();
然后们分析下结果吧。
//16s时我们开始点餐
开始点餐Sun Oct 18 00:00:16 CST 2020
我:好饿啊,好想吃饭啊
我:咋害没给我发消息呢!
//20s后,外卖小哥去取餐
外卖小哥正在赶往商家取餐...Sun Oct 18 00:00:36 CST 2020
//10s中等待这个倒霉的商家弄好
外卖小哥取餐成功,正在奔向你Sun Oct 18 00:00:46 CST 2020
外卖小哥你的外卖距离你还有10m,注意取餐哟
//10s后我就拿到啦
我:终于来了他妈到了Sun Oct 18 00:00:56 CST 2020
我:吃外卖Message(content=您好,你的外卖已到,请取餐)
好玩吗哈哈?就这样我们就学会了一个设计模式喽。
结尾语
从这个设计模式中,可以衍生出许多值得学习的东西哟。阅读完有啥好的想法,可以私聊我哟。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。