算是开始读ZeroMQ(java)的代码实现了吧,现在有了一个大体的了解,看起来实现是比较的干净的,抽象什么的不算复杂。。。
这里先来看看它的I/O线程的实现吧,顺带看看是如何实现组件的通信的。。。。
首先要搞清楚I/O线程的实现,就先要弄懂一个类型,Poller(zmq.Poller.java),可以将其看成是对selector的一个封装,同时它还要管理定时事件,看了这么多代码,发现基本上都是在实现I/Oselect的地方完成了定时的实现。。。。
好了,不说太多闲话了,来看看它的继承体系吧:
这里还将依赖关系也标出来了,首先继承自PollerBase抽象类,然后实现了Runnable接口,自己还会创建一个Thread对象。。。看了这个图,基本上就已经能够知道Poller的运行原理了吧。。。。
这里先来看看PollerBase的实现吧,它其实主要是用来管理定时的,那么先来看看他的一些重要的属性和定义:
private final AtomicInteger load; //这个load其实就是当前poller里面注册的channel的数量
//这里是要注册的超时是事件
private final class TimerInfo {
IPollEvents sink; //事件回调
int id;
public TimerInfo(IPollEvents sink_, int id_) {
sink = sink_;
id = id_;
}
}
private final Map<Long, TimerInfo> timers; //这里记录所有的超时对象,key是时间
private final Map<Long, TimerInfo> addingTimers; //等待加入的超时事件
前面的一个原子Integer是用于记录负载的,用于记录当前poller里面一共注册了多少I/O对象。。。然后是超时事件的定义,sink是超时的事件回调函数,里面有相应的方法,timer就记录了所有的超时事件,addingTimers是需要加入的超时事件。。这里的key都是超时的时间,value就是超时对象了。。。
这里就来看两个主要的方法就好了吧,先来看看如何加入超时事件:
//添加一个超时事件
public void add_timer (long timeout_, IPollEvents sink_, int id_) {
long expiration = Clock.now_ms () + timeout_; //计算超时的时间
TimerInfo info = new TimerInfo(sink_, id_); //创建超时对象
addingTimers.put(expiration, info); //将其添加到adding里面去
}
代码应该很简单能够看明白吧,第一个参数是超时时间,第二个参数是回调方法,第三个参数是ID,首先加上当前的时间就算出了超时的时间,然后创建超时对象,这里先是将其放入了addingTimers里面,而不是直接放到了timer里面,。。。
那么接下来来看看如何执行所有的超时的方法吧:
//执行所有的超时事件,返回下一个超时还剩下的时间
protected long execute_timers() {
if (!addingTimers.isEmpty()) { //如果当前还有需要添的超时时间,那么需要将其添加进去
timers.putAll(addingTimers);
addingTimers.clear();
}
//没有超时事件
if (timers.isEmpty())
return 0L;
//获取当前的时间
long current = Clock.now_ms ();
//遍历所有的超时时间,这里是从最小的开始的
Iterator<Entry <Long, TimerInfo>> it = timers.entrySet().iterator();
while (it.hasNext()) {
Entry <Long, TimerInfo> o = it.next();
// If we have to wait to execute the item, same will be true about
// all the following items (multimap is sorted). Thus we can stop
// checking the subsequent timers and return the time to wait for
// the next timer (at least 1ms).
//如果超时的时间大于当前的时间,那么表示还没有超时,
if (o.getKey() > current) {
return o.getKey() - current; //