前言
爲了實現更高的併發性能,避免單一訪問阻塞通訊節點。在java中使用Channel的方式進行。利用Selector作爲訪問事件的觸發,管理多個操作隊列,如Read、Write、Connection、Accept等。
不同的操作分配給不同的線程進行。實現服務器的併發訪問。
提供一個簡單的設計思路。
線程 | 職責 | 接受事件 |
---|---|---|
Accept #0 | 啓動服務器端口,監聽客戶傳來的連接請求。接收請求以後,對客戶的連接進行設置,將客戶的OP_Read請求註冊給Reader的Selector | SelectKey.OP_Accept |
Reader #1 | 阻塞式/非阻塞式偵聽用於Read事件的Selector是否被選擇。如果被選擇,需要相應的讀取操作,接收客戶傳來額數據 | SelectKey.OP_Read |
Writer #2 | 阻塞式/非阻塞式偵聽用於Write事件的Selector是否被選擇,這個Write事件可以是Reader線程觸發的,也可以是另外的線程觸發。 | SelectKey.OP_Write |
各線程的共通處
- 都需要使用
Selector.Open()
初始化自身的Selector。這個Selector可以理解爲一個隊列。只要註冊了線程的Selector的對應事件,就會觸發這個線程的Selector.selecte()
事件 - 線程每處理一個
Selector.SelectedKey
,需要使用迭代器的remove
方法將這個被選擇的Key清除,代表這個Key已經被處理過了
Accept線程
//後續補充
Read線程
//後續補充代碼
Write線程
這個線程的Selector.select
事件有兩種觸發方式
- 如上面所講的,在將一個
SocketChannel.key
註冊到Wirte線程的Selector
時,會自動觸發一次被選擇事件。 - 如果已經註冊給Write線程的Selector,這個時候可以調用
SocketChannel.key.interestOps()
方法,輸入需要進行的操作,那麼會持續觸發Selector.selecte
事件。只有使用SocketChannel.key.interestOps(0)
清除纔會停止選擇。這意味和,如果SocketChannel.key
已經註冊給Write進程,且使用了SocketChannel.key.interestOps()
喚醒某種操作。同樣需要使用SocketChannel.key.interestOps(0)
清除該喚醒