2009-07-10 83 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