多线程之设计模式之Listener设计模式(观察者设计模式)

虽然设计模式我们一般中用的很少,但是作为程序员设计模式是我们自我修养的一部分,so最近学习了一个设计模式.记下来喽:

观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

这是百科上面的原话,为了理解清楚我们上一张图

多线程之设计模式之Listener设计模式(观察者设计模式)_第1张图片

简单来说

Subject相当于任务中心   Observe 里面有很多方法继承 相当于每个实现是感知  Subject干了什么动作

当 Demo 调用Subject的时候 就会通知Observe, Observe就会被动的通知 它干了什么(肤浅的理解)

上代码,首先我们确定几个类:

1Subject类,还有Observer类是必须的 

 

package com.hegaojian.concurrency.chapter4;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassNameSubject
 * @Description TODO
 * @AuthorSJ217110601
 * @Date2018/7/13 16:06
 * @Version 1.0
 **/
public class Subject {
    //一个任务里面有一堆的Observe
    private List observerList = new ArrayList();
    //定义一个发生变化的东西(状态)
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {//如果这个状态没变就返回
        if (state == this.state) {
            return;
        }
        this.state = state;
        notifyAllObserver();//通知其他Observer做动作
    }

    //附上到那Observer 也就是说添加那个Observer
    public void attach(Observer observer) {
        observerList.add(observer);
    }

    //通知到所有的
    private void notifyAllObserver() {
        observerList.stream().forEach(Observer::updata);
    }
}
 

定义完之后我们应该定义Observer

 

public abstract class Observer {
    //别人改变了数据就通知到我了 构造函数
    public Observer(Subject subject) {
        this.subject = subject;
        //吧这个通知添加进去
        subject.attach(this);
    }
    //定义一个任务中心
    protected Subject subject;
    //定义一个方法
    public abstract void updata();
}
 

我们按照图 在定义几个Observer的子类,

 

public class BinaryObserver extends Observer {
    public BinaryObserver(Subject subject) {
        super(subject);
    }

    @Override
    public void updata() {
        System.out.println("BinaryObserver :" + Integer.toBinaryString(subject.getState()));
    }
}
public class OtalObserver extends Observer {
    public OtalObserver(Subject subject) {
        super(subject);
    }

    @Override
    public void updata() {
        System.out.println("Otal 八进制" + Integer.toOctalString(subject.getState()));
    }
}
 

定义了两个子类,也就是相当于模拟业务中的其他操作

 

public class ObserverClient {
    public static void main(String[] args) {
        //主题
        final Subject subject = new Subject();
        new BinaryObserver(subject);
        new OtalObserver(subject);
        System.out.println("====================");
        subject.setState(10);
        System.out.println("==========");
        subject.setState(10);

        System.out.println("============");
        subject.setState(15);
    }
}

我们看到上面这个类是客户扣的类,首先我们第一次赋值10,然后都去通知Observer类,去通知它我要改变了,这样就是主动通知,而Observer类则是备用接收到了通知,Subject的状态改变触发了相关事件

====================
BinaryObserver :1010
Otal 八进制12
==========
============
BinaryObserver :1111

Otal 八进制17

我们看到了输出结果,当第二次也是10的时候,它的Observer的子类不会感知到,当数字一变这样就通知了它的Observer类

==================================================================

那么在多线程的环境下怎么实现呢?

我们思路还是那个思路,这里只不过是要考虑到线程安全的问题,在这里我们模拟:根据一个List里面的id通过多线程的方式去查询数据库,但是我们得清楚的感知到线程里面的每一个动作都做到哪儿,包括知否出错等

我们先定义一个多线程的

public abstract class ObserverRunnable implements Runnable {
    //(生命体征的)监听器(也就是说用这个去)
    final protected LifeCycleListener listener;
    //构造方法
    public ObserverRunnable(LifeCycleListener listener) {
        this.listener = listener;
    }
    //去通知被的线程
    protected void NotifyChange(final RunnableEvent event) {
        listener.OnEvent(event);
    }
    //枚举了三个类型
    public enum RunnableStatu {
        RUNN, ERROR, DONE
    }

    public static class RunnableEvent {
        private final RunnableStatu runnableStatu;

        //那个线程在执行它的过程中出现了问题
        private final Thread thread;
        //失败了的话什么原因引起的失败呢
        private final Throwable throwable;

        public RunnableEvent(RunnableStatu runnableStatu, Thread thread, Throwable throwable) {
            this.runnableStatu = runnableStatu;
            this.thread = thread;
            this.throwable = throwable;
        }

        public RunnableStatu getRunnableStatu() {
            return runnableStatu;
        }

        public Thread getThread() {
            return thread;
        }

        public Throwable getThrowable() {
            return throwable;
        }
    }
}
public interface LifeCycleListener {
//通知的方法
    void OnEvent(ObserverRunnable.RunnableEvent event);
}
 

 

public class ThreaLiftListenerImpl implements LifeCycleListener {
    //因为在多线程环境出现共享数据的问题所以需要枷锁 这里简单定义一下锁
    private final Object LOCK = new Object();

    //一个ID一个线程的去查做事情
    public void concurrentQuery(List ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }
        //多线程去执行
        ids.stream().forEach(id -> new Thread(new ObserverRunnable(this) {
            @Override
            public void run() {
                try {
                    //正常运行
                    NotifyChange(new RunnableEvent(RunnableStatu.RUNN, Thread.currentThread(), null));
                    System.out.println("query for id " + id);
                    //模拟查询消耗的时间
                    Thread.sleep(1000L);
                    //正常结束
                    NotifyChange(new RunnableEvent(RunnableStatu.DONE, Thread.currentThread(), null));
                } catch (Exception e) {
                    //遇到异常处理
                    NotifyChange(new RunnableEvent(RunnableStatu.ERROR, Thread.currentThread(), e));
                }
            }
        }, id).start());
    }

    @Override
    public void OnEvent(ObserverRunnable.RunnableEvent event) {
        {
            //这里我们加了锁,因为在多线程的环境下所以要加锁
            synchronized (LOCK) {
                //我们只是模拟了输出,这在业务中会写到日志里面去
                System.out.println("The runnable [" + event.getThread().getName() + "] data changed and state is [" + event.getThrowable() + "]");
                if (event.getThrowable() != null) {
                    System.out.println("The runnable [" + event.getThread().getName() + "] process failed.");
                    event.getThrowable().printStackTrace();
                }
            }
        }
    }

}
 

模拟客户端

public class CurrentListenerClient {
    public static void main(String[] args) {
        new ThreaLiftListenerImpl().concurrentQuery(Arrays.asList("1","2"));
    }

}

The runnable [2] data changed and state is [null]
The runnable [1] data changed and state is [null]
query for id 1
query for id 2
The runnable [2] data changed and state is [null]

The runnable [1] data changed and state is [null]

输出结果的分析我,这样我们可以观察到线程里面每个数据的状态,还有对应的一些操作,那么如果遇到错误我们会怎么办?

多线程之设计模式之Listener设计模式(观察者设计模式)_第2张图片

模拟了错误

多线程之设计模式之Listener设计模式(观察者设计模式)_第3张图片

这样便可以观察到每一个线程里面的状态.

(如有错误请多指教!!!)

参考书(java多线程设计模式)

分享地址:https://pan.baidu.com/s/1jIkt94M 密码:qwb8

你可能感兴趣的:(多线程设计模式,多线程学习总结)