Java - 用于非阻塞套接字的多个线程中的多个选择器

时间:2009-07-10 19:30:04

标签: java multithreading css-selectors nio

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

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

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

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

2 个答案:

答案 0 :(得分:3)

如果必须使用此单插槽连接,则必须将数据从数据处理本身接收和写入数据的过程分开。您不必委派频道。通道就像一辆公共汽车。总线(管理通道的单线程)必须读取数据并将其写入(线程安全的)输入队列,包括所需的信息,因此您的客户端线程可以从中获取正确的数据报包。队列。如果客户端线程喜欢写入数据,那么该数据将被写入输出队列,然后由通道线程读取以将数据写入通道。

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

答案 1 :(得分: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的实现,如here所述。