6

我正在编写一个 Java 应用程序,它将实例化一个类的对象,以表示已连接并注册到我的应用程序另一端的外部系统的客户端。

每个客户端对象中都有两个嵌套类,分别代表前端和后端。前端类将不断地从实际客户端接收数据,并将指示和数据发送到后端类,后端类将从前端获取数据并使用适当的格式和协议将其发送到外部系统该系统需要。

在设计中,我们希望将客户端对象的每个实例化为一个线程。然后,在每个线程内自然会有两个套接字 [EDIT],每个套接字都有自己的 NIO 通道[/EDIT],一个客户端,一个系统端分别位于前端和后端。但是,这现在引入了对非阻塞套接字的需求。我一直在阅读这里的教程,该教程解释了如何在主线程中安全地使用 Selector 来处理所有具有连接的线程。

但是,我需要的是多个选择器——每个选择器都在自己的线程中运行。通过阅读上述教程,我了解到 Selector 中的键集不是线程安全的。这是否意味着如果我尝试为每个选择器提供自己的一对套接字和通道,在他们自己的对应线程中实例化的单独选择器可能会产生冲突的键?将选择器向上移动到主线程的可能性很小,但根据我给出的软件要求,这远非理想。感谢您的帮助。

4

2 回答 2

3

如果你必须使用这个单一的套接字连接,你必须把从通道接收和写入数据的过程与数据处理本身分开。您不必委托渠道。通道就像公共汽车。总线(管理通道的单线程)必须读取数据并将其写入(线程安全)输入队列,包括所需的信息,以便您的客户端线程可以从中获取正确的数据报包队列。如果客户端线程喜欢写入数据,则将该数据写入输出队列,然后由通道线程读取该队列以将数据写入通道。

因此,从使用此连接的参与者之间共享连接的概念及其不可预测的处理时间(这是阻塞的主要原因),您转向异步数据读取、数据处理和数据写入的概念。因此,不再是无法预测的处理时间,而是读取或写入数据的时间。非阻塞意味着数据流尽可能保持不变,尽管处理该数据需要多长时间。

于 2009-07-10T21:02:40.000 回答
3

只要您不使用两个选择器实例注册具有相同兴趣(OP_READ / OP_WRITE 等)的相同频道,就可以使用多个选择器。使用多个选择器实例注册相同的通道可能会导致 selector1.select() 可能会消耗 selector2.select() 可能感兴趣的事件的问题。

大多数平台上的默认选择器都是基于 poll() [或 epoll()] 的。

Selector.select 在内部调用int poll( ListPointer, Nfdsmsgs, Timeout) method.

        where the ListPointer structure can then be initialized as follows:

    list.fds[0].fd = file_descriptorA;
    list.fds[0].events = requested_events;
    list.msgs[0].msgid = message_id;
    list.msgs[0].events = requested_events;

也就是说,我建议使用 ROX RPC nio 教程中提到的单个选择线程。NIO 的实现依赖于平台,很可能在一个平台上工作的东西可能在另一个平台上不工作。我也看到过小版本的问题。例如,AIX JDK 1.6 SR2 使用基于 poll() 的选择器 - PollSelectorImpl 和对应的选择器提供程序作为 PollSelectorProvider,我们的服务器运行良好。当我迁移到使用基于 pollset 接口的优化选择器 (PollSetSelectorImpl) 的 AIX JDK 1.6 SR5 时,我们的服务器在 select() 和 socketchannel.close() 中经常遇到挂起。我看到的一个原因是我们在我们的应用程序中打开了多个选择器(与理想的选择线程模型相反)以及所描述的 PollSetSelectorImpl 的实现在这里

于 2009-10-07T03:18:54.770 回答