前言
为了实现更高的并发性能,避免单一访问阻塞通讯节点。在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)
清除该唤醒