【问题标题】:Java - Multiple selectors in multiple threads for nonblocking socketsJava - 用于非阻塞套接字的多个线程中的多个选择器
【发布时间】:2010-11-09 20:06:36
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: java multithreading css-selectors nio


    【解决方案1】:

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

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

    【讨论】:

    • 恐怕我对你的回答有点困惑。你是说一个频道本身就是一个线程,一个频道是它自己的线程,还是我应该设置和轮询与客户端不同的线程中的通道?我在原始帖子中可能不清楚,每个客户端对象将有两个套接字,以及在应用程序的任一侧用于通信的两个通道。最初学会了用 C 编写套接字,我熟悉非阻塞与非阻塞的概念,并特别选择非阻塞是因为需要多路通信。
    • 这会很冒险,所以请不要投反对票......系统问题淹没了讨论 - 请参阅:ibm.com/developerworks/aix/library/au-pollset/index.html,它给出了更好的答案。通道不被设计为线程thingamabob:它被设计为在希望良好的io和线程性能的编程环境中运行。整个问题都被实时 JSR 中描述的问题所笼罩……上面的链接给出了了解此事的工程师对此事的讨论。我做了一些早期的测试,它不像看起来那样。
    【解决方案2】:

    只要您不使用两个选择器实例注册具有相同兴趣(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 所述。

    【讨论】:

      猜你喜欢
      • 2010-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-13
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多