package com.github.techrobby.SimplePubSub;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class Pubsub implements Runnable {
//操作对象: 包括消息的主题类型和消息的具体内容
public class Operation {
public Operation(String type, Object o) {
this.type = type;
this.payload = o;
}
public final String type;
public final Object payload;
}
//监听器,具体监听器要实现这个接口
public interface Listener {
//并在自己的实现方法里,对接收到某种类型的主题做出具体的实现
public void onEventReceived(String type, Object object);
}
private int NUMBER_OF_THREADS = 1;
//并发线程池
ExecutorService ex;
//消息的发布和订阅通过队列存取
private final BlockingQueue<Operation> mQueue;
//topicType, 实现Listener的实现类. 同一个topic可以有多个订阅者
private Map<String, Set<Listener>> listeners;
//单例
private static Pubsub _instance;
//双重检查
public static Pubsub getInstance() {
if (_instance == null) {
synchronized (Pubsub.class) {
if (_instance == null)
_instance = new Pubsub();
}
}
return _instance;
}
private Pubsub() {
listeners = new ConcurrentHashMap<String, Set<Listener>>();
mQueue = new LinkedBlockingQueue<Operation>();
ex = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
//自己也是一个线程
ex.submit(this);
}
public void addListener(String type, Listener listener) {
add(type, listener);
}
public void addListeners(Listener listener, String... types) {
for (String type : types) {
add(type, listener);
}
}
//往指定的topic中添加一个监听器.
private void add(String type, Listener listener) {
//topic的订阅者是一个无序集合
Set<Listener> list = listeners.get(type);
//集合为空:比如第一个订阅者,先创建一个集合,准备用来将当前订阅者加入集合中
if (list == null) {
// take a smaller lock 和单例的获取一样,双重检查锁, 所以是线程安全的
synchronized (this) {
if ((list = listeners.get(type)) == null) {
list = new CopyOnWriteArraySet<Listener>();
//listeners首先是一个Map.先往Map的topicType中放入一个空的List
//因为listeners要保存所有topic的所有订阅者
listeners.put(type, list);
}
}
}
//再往List中添加当前订阅者
list.add(listener);
}
public void removeListener(String type, Listener listener) {
remove(type, listener);
}
public void removeListeners(Listener listener, String... types) {
for (String type : types) {
remove(type, listener);
}
}
private void remove(String type, Listener listener) {
Set<Listener> l = listeners.get(type);
//如果主题的订阅者本来就没有,就不需要移除, 存在才需要移除
if (l != null) {
l.remove(listener);
}
}
public boolean publish(String type, Object o) {
//这个主题有订阅者才能发送成功,否则没有订阅者,发送了也没用
Set<Listener> l = listeners.get(type);
if (l != null && l.size() >= 0) {
//队列只保存了要发送到的主题类型和消息内容. 不保存这个主题的订阅者有哪些人
mQueue.add(new Operation(type, o));
return true;
}
return false;
}
@Override
public void run() {
Operation op;
while (true) {
try {
//从队列中获取出一个元素
op = mQueue.take();
} catch (InterruptedException e) {
continue;
}
String type = op.type;
Object o = op.payload;
//这个主题的订阅者列表
Set<Listener> list = listeners.get(type);
if (list == null || list.isEmpty()) continue;
//触发监听事件, 调用订阅者自己的接收方法
for (Listener l : list) {
l.onEventReceived(type, o);
}
}
}
}