在Java NIO Reactor Pattern中的不同线程中调度事件处理程序

时间:2016-07-15 15:14:02

标签: java selector nio reactor

我正在使用Reactor Pattern使用java NIO编写一个简单的服务器应用程序。据我了解,Reactor类负责收集Events(例如:OP_ACCEPT,OP_READ,OP_WRITE)。

相对EventHandler将负责特定任务。因此处理程序应该能够异步运行在不同的线程中。

这是代码:enter image description here

当我运行它时,它显示一些问题,while循环继续运行,Selector保持返回readyOps设置为(1,4,16)。我猜是因为AcceptHanndler没有以阻止的方式处理OP_ACCEPT。因此,即使从迭代器中删除密钥,在select()调用之后,它也会再次出现。

我不能在单独的线程中将eventHander作为runnable运行吗?

我想到了edge-triggeredlevel-triggered模型的概念。原因是选择器是在level-triggered模型中运行吗?

1 个答案:

答案 0 :(得分:2)

是的,选择器是水平触发的。您的案例中的标准工作流将遵循:在您检测到该通道可接受之后,从Selector中取消该键,并且仅在将该键传递给事件处理程序线程之后。事件处理程序线程将完成接受并且1)再次为OP_ACCEPT注册服务器套接字; 2)根据您要实现的协议,为OP_READ和/或OP_WRITE注册接受的客户端套接字。或者,您可以在主线程中完成接受(出于性能原因,如果有一大堆连接客户端)。

实际上,按操作类型区分线程是不可扩展的,并且由于数据局部性差,可能在SMP系统中性能较差。最好将每个客户端套接字锁定到单个线程。高性能Java服务器通常通过使一个线程专门用于接受(仅在那里注册单个ServerSocket)和N个工作线程来实现客户端套接字来实现。接受线程在循环中工作:

  1. 阻止select()直到新客户端到达
  2. 完成接受
  3. 选择负载最少的工作线程并转移新接受的客户端套接字的所有权
  4. 每个工作线程都有自己的Selector和一组客户端套接字,负责读/写这些套接字。