Guarded-Suspension模式


Guarded-Suspension模式,即保护性暂停模式,在生活中是很常见的哟。比如说我们在买奶茶后等待取餐、点外卖后等待取餐。这些生活例子都有一个特征,就是需要等待另外一个人搞定后,我们才可以行动。而我们今天介绍的这个设计模式,就是等我准备好你再行动的想法哦。那么跟着我往下学习这个模式吧。

解释图

image-20201017232355128
旁边的解释图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=您好,你的外卖已到,请取餐)

好玩吗哈哈?就这样我们就学会了一个设计模式喽。

结尾语

从这个设计模式中,可以衍生出许多值得学习的东西哟。阅读完有啥好的想法,可以私聊我哟。


Fudada
0 声望1 粉丝

喜欢画画,喜欢后端。