network-AsynchronousSocketChannel
AsynchronousServerSocketChannel 和 AsynchronousSocketChannel 的实现借助于 AsynchronousChannelGroup 的线程池,当执行一个异步的时候,可以将这个异步操作提交到 AsynchronousChannelGroup 的线程池中。
AsynchronousChannelGroup 对象可以多个 Channel 所共享。
1 | // Opens an asynchronous server-socket channel. |
当使用无参数的方法,获得一个 AsynchronousServerSocketChannel 的实例的时候,或者调用第二个方法时传入 null 值的时候,创建的这个将会共享整个 JVM 中惟一的一个 AsynchronousChannelGroup 对象实例。
在不同的操作系统平台上 AsynchronousChannelGroup 的实现也有所有不同。
linux
EPollPort
unix
SolarisEventPort
windows
Iocp
AsynchronousChannelGroup 的作用:
A AsynchronousChannelGroup has an associated thread pool
- tasks are submitted to handle I/O events
- dispatch to completion-handlers that consume the result of asynchronous operations performed on channels in the group
- execute other tasks required to support the execution of asynchronous I/O operations.
AsynchronousServerSocketChannel
unix
SolarisEventPort
UnixAsynchronousServerSocketChannelImpl
linux
EPollPort
内部维护了哪些数据,下面方法是如何按照这些数据展开的。
创建
1 |
使用
UnixAsynchronousServerSocketChannelImpl
windows
WindowsAsynchronousServerSocketChannelImpl
AsynchronousSocketChannel
- unix
UnixAsynchronousSocketChannelImpl
- windows
WindowsAsynchronousSocketChannelImpl
AsynchronousChannelGroup
AsynchronousChannelGroup 创建时会关联一个线程池,如果不进行配置,则默认的线程池大小是:
1 | // 默认的 poolsize 是当前 JVM 所运行的机器的处理器个数。 |
由此,可见,当创建一个 AsynchronousChannelGroup 时,至少会有两个线程,执行 上面的 task 任务。
所以,当下面的调用发生在一个具有4个处理器的机器上时,会创建5个线程。
1 | defaultPort = new EPollPort(this, ThreadPool.getDefault()).start(); |
这5个线程中的第一个线程是内部线程。
其余的4个线程是 ThreadPoolExecutor 中的4个线程。
这5个线程将执行 sun.nio.ch.EPollPort.EventHandlerTask
任务。
EventHandlerTask
EventHandlerTask
实现的逻辑如下:
- 从 queue 中获取事件
- 如果获得的事件是 NEED_TO_POLL ,则执行 EventHandlerTask.poll 方法
- poll 方法将在 pollfd 上执行
epoll_wait
方法,直到返回 epoll_wait
方法返回之后,放置初始化对应的事件 Event 添加到 queue 中- run 方法从 queue 中获得事件,进行相应的处理
- 调用 channel 的 onEvent 方法。
调用 channel 的异步操作
- AsynchronousServerSocketChannel.accept
- AsynchronousSocketChannel.connect
- AsynchronousSocketChannel.read
- AsynchronousSocketChannel.write
这四个方法的实现,最终都是调用 startPoll 来实现。startPoll 的作用就是向 epfd 注册当前 fd 所关心的事件。
1 | // EPollPort.startPoll 方法。 |
事件的处理 onEvent
1 | // isPooledThread 表示当前线程是否是 线程池中的线程。 |
资源的回收
可见当使用 AsynchronousServerSocketChannel 时系统,就会创建一个默认的 AsynchronousChannelGroup 这个对象,会分配一个 epoll 对象,及至少 2 个线程。这些都是系统资源,所以当使用完 AsynchronousServerSocketChannel 的时候,需要正确的回收这些资源。
隐式关闭
AsynchronousServerSocketChannel 在关闭的时候,会从 AsynchronousChannelGroup 对象上进行 unregister 操作。unregister 方法中会进行判断,如果当前 Group 中已经没有 channel 了,则AsynchronousChannelGroup 会执行 shutdown 操作。正是这个 shutdonwNow
方法调用会回收上面些系统资源。
显式关闭
AsynchronousChannelGroup 接口提供了 shutdown
和 shutdownNow
方法用来显式关闭 AsynchronousChannelGroup 所使用的系统资源。