Groups
the asynchronous API introduces a class named AsynchronousChannelGroup, which presents the concept of an asynchronous channel group, in which each asynchronous channel belongs to a channel group (the default one or a specified one) that shares a pool of Java threads.
These threads receive instructions to perform I/O events and they dispatch the results to the completion handlers.
Asynchronous channels are safe for use by multiple concurrent threads. Some channel implementations may support concurrent reading and writing but may not allow more than one read and one write operation to be outstanding at any given time.
在异步AIP中AynchronousChannelGroup 表示 asynchronous chennel group 的概念。 每一个 asynchronous channel 都属于一个指定的group.
同时,group 共享java线程。这些线程接收异步i/o操作事件同时把结果分发到completion handler.
asynchronous channel group操作线程池和被所有线程共享的自由。 channel 被拥有channel 的group影响,当group关闭时,channel也是关闭的。
Default Group
Besides the developer’s created groups, JVM maintains a system-widedefault groupthat is constructed automatically, useful for simple applications.
Besides the developer’s created groups, JVM maintains a system-widedefault groupthat is constructed automatically, useful for simple applications.
When a group is not specified, or anullis passed instead, the asynchronous channels are bound, at construction time, to the default group.
public static AsynchronousServerSocketChannel open()throws IOException
This method returns an asynchronous server socket channel that is bound to the default group.
This method returns an asynchronous server socket channel that is bound to the default group.
除了用户自定义groups,java虚拟机本身保留系统默认的group,默认group被自动创建。 默认group可以用来创建简单应用程序。
当AsynchronousServerSocketChannel.open()方法调用时,默认group将自动创建,AsynchronousServerSocketChannel 实例将自动绑定到默认的group上面
If the default group does not satisfy your needs, theAsynchronousChannelGroupclass provides three
methods for creating your own channel groups. For AsynchronousServerSocketChannel,
AsynchronousSocketChannel, andAsynchronousDatagramChannel(unavailable as of this writing), the
channel group is passed on creation in the open() method of each one.AsynchronousFileChanneldiffers
from the other channels in that, in order to use a custom thread pool, theopen()method takes an
ExecutorServiceinstead of anAsynchronousChannelGroup.
Now, let’s see what the advantages and disadvantages of each supported thread pool are; these characteristics will help you to decide which one
is proper in your case.
is proper in your case.
当默认group不能满足应用程序需要时,Asynchronouschannelgroup提供三种方式创建用户自定义group.
Fixed Thread Pool
You can request a fixed thread pool by calling the following AsynchronousChannelGroup method:
public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,ThreadFactory threadFactory) throws IOException
This method creates a channel group with a fixed thread pool. You must specify the factory to use when creating new threads and the number of threads.
The life cycle in a fixed thread pool follows a simple scenario:
a thread waits for an I/O event,completes I/O for the event, invokes a completion handler, and goes back to wait for more I/O events (the kerneldispatches events directly to these threads).
When the completion handler terminates normally, the thread returns to the thread pool and waits for the next event.
But if the completion handler does not complete in a timely manner, then it is possible to enter into an indefinitely blocking.
If all threads “deadlock” inside a completion handler, then the application is blocked until a thread is available to execute again, and any new event will be queued until a thread is available.
In the worst-case scenario, no thread can get free and the kernel can no longer execute anything.
This issue may be avoided if you don’t use blocking or long operations inside a completion handler.
Also, you may use a cached thread pool or timeouts for avoiding this issue.
第一种为固定数量线程池。
第一种为固定数量线程池。
主要: 固定数量线程池的生命周期遵循一个简单的方案:
一个线程等待异步I/O 事件,完成I/O事件,调用competion handler方法,然后继续等待更多的I/O事件。(注意:操作系统内核分发事件到这些线程中)。
当一个competion handler 正常结束时,线程将回到线程池中,继续等待下一个I/O操作事件。
如果completion handler没有在一定事件内完成,有可能进入阻塞状态,如果所有的线程都死锁,那么应用程序进程将阻塞,直到存在线程可以继续执行。
最糟糕的情况是,所有的线程都死锁不再执行任何事情。
这个问题可以通过在competion handler中不使用任何锁机制或者长时间的操作。
同时,可以使用缓冲线程池或者超时来避免这种问题。
Cached Thread Pool
You can request a cached thread pool by calling the followingAsynchronousChannelGroupmethod:
public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,int initialSize) throws IOException
This method creates an asynchronous channel group with a given thread pool that creates new threads as needed.
You just need to specify the initial number of threads and an ExecutorService that creates new threads as needed.
It may reuse previously constructed threads when they are available.
In this case the asynchronous channel group will submit events to the thread pool that simply invoke completion handlers.
In this case the asynchronous channel group will submit events to the thread pool that simply invoke completion handlers.
But if the thread pool simply invokes the completion handlers, then who does the hard work and performs the I/O operations? The answer is the hidden thread pool.
This is a set of separate threads that waits for incoming I/O events.
More precisely, the kernel I/O operations are handled by one or more invisible internal threads that dispatch events to a cached pool, which in turn
invokes completion handlers.
The hidden thread pool is important because it greatly reduces the probability that the application
will be blocked (it solves the fixed thread pool issue) and guarantees that the kernel will be able to complete its I/O operations.
invokes completion handlers.
The hidden thread pool is important because it greatly reduces the probability that the application
will be blocked (it solves the fixed thread pool issue) and guarantees that the kernel will be able to complete its I/O operations.
But we still have an issue, because the cached thread pool needs unbounded queuing, which can make the queue grow infinitely and cause
OutOfMemoryError—so monitor the queue (avoid locking all the threads and avoid feeding the queue forever).
Avoiding the use of blocking or long operations inside completion handlers is still a good idea.
如果线程池执行调用completion handler ,到底谁来执行I/O操作呢??? 答案是:隐藏线程池。
隐藏线程池是另外一部分线程来处理连接I/O事件。
更准确的说,操作系统内核通过一个或者多个不可见内部线程执行IO操作同时分发事件到缓存线程池,缓存线程池回来调用completion handler.
隐藏线程池对于降低应用程序死锁的概率非常重要和确保内核可以完成I/O 操作。
为了避免死锁活或者长时间在completion handler的操作 使用缓冲线程池是非常重要的。