2009-07-10 60 views
6

我正在写一个Java应用程序,将实例化一个类的对象来表示对我的应用程序的另一端连接,并与外部系统注册客户。爪哇 - 在多线程多选择的非阻塞套接字

每个客户对象在其内具有两个嵌套类,代表前端和后端。前端类将连续地从实际的客户端接收数据,和发送指示和数据传送到后端类,这将需要从前端该数据,并将其在使用适当的格式和协议发送到外部系统该系统需要。

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

但是,我需要的是多个选择 - 在自己的线程每一个操作。从阅读前面提到的教程,我了解到Selector中的键集不是线程安全的。这是否意味着,如果我试图给它们各自的套接字和通道对,单独的Selectors在自己的reponctive线程中实例化可能会产生冲突的关键字?将选择器移动到主线程是一种微小的可能性,但基于我所给出的软件要求,这是远远不够理想的。感谢您的帮助。

回答

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所述。

3

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

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

+0

恐怕我对你的回答感到困惑,你是说频道本身就是一个线索,频道是它自己的线索,还是我应该单独设置和轮询频道线程从客户端? 我可能没有在我的原始文章中清楚,每个客户端对象将有两个套接字和两个通道在应用程序的任何一方进行通信。熟悉非阻塞和非阻塞的概念,并且特别选择了非阻塞,因为要求多路复用通信。 – 2009-07-11 14:37:57