在启动程序时,NioSocketAcceptor 绑定本地端口时,NioSocketAcceptor(AbstractPollingIoAcceptor<S,H>).startupAcceptor() 内部类为一个线程类,用来接收新socket链接。
同时,Acceptor启动IoProcess线程来处理IO读取操作。
Acceptor线程调用堆栈如下:
NamePreservingRunnable.<init>(Runnable, String)
NioSocketAcceptor(AbstractIoService).executeWorker(Runnable, String)
NioSocketAcceptor(AbstractIoService).executeWorker(Runnable)
NioSocketAcceptor(AbstractPollingIoAcceptor<S,H>).startupAcceptor()
NioSocketAcceptor(AbstractPollingIoAcceptor<S,H>).bindInternal(List<SocketAddress>)
NioSocketAcceptor(AbstractIoAcceptor).bind(Iterable<SocketAddress>)
NioSocketAcceptor(AbstractIoAcceptor).bind(SocketAddress)
IoProcess线程启动如下:
SimpleIoProcessorPool<S>.<init>(Class<IoProcessor<S>>, Executor, int, SelectorProvider) line: 160
SimpleIoProcessorPool<S>.<init>(Class<IoProcessor<S>>) line: 115
NioSocketAcceptor(AbstractPollingIoAcceptor<S,H>).<init>(IoSessionConfig, Class<IoProcessor<S>>) line: 106
NioSocketAcceptor.<init>() line: 61
public abstract class AbstractPollingIoAcceptor
{
/**
* Define the number of socket that can wait to be accepted. Default
* to 50 (as in the SocketServer default).
*/
protected int backlog = 50;
//构造函数
protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Class<? extends IoProcessor<S>> processorClass)
{
this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass), true, null);
}
}
//创造默认线程数量为CPU数量+1
/** The pool table */
private final IoProcessor<S>[] pool; //在这里是创建IoProcess线程数组.
/** The default pool size, when no size is provided. */
private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;
/**
* Creates a new instance of SimpleIoProcessorPool with a default
* size of NbCPUs +1.
*
* @param processorType The type of IoProcessor to use
*/
public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType)
{
this(processorType, null, DEFAULT_SIZE, null);
}
public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType, Executor executor, int size, SelectorProvider selectorProvider) {
if (processorType == null)
{
throw new IllegalArgumentException("processorType");
}
if (size <= 0) {
throw new IllegalArgumentException("size: " + size + " (expected: positive integer)");
}
// Create the executor if none is provided
createdExecutor = (executor == null);
if (createdExecutor) {
this.executor = Executors.newCachedThreadPool();
// Set a default reject handler
((ThreadPoolExecutor) this.executor).setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
} else {
this.executor = executor;
}
pool = new IoProcessor[size];
boolean success = false;
Constructor<? extends IoProcessor<S>> processorConstructor = null;
boolean usesExecutorArg = true;
try {
// We create at least one processor
try {
try {
processorConstructor = processorType.getConstructor(ExecutorService.class);
pool[0] = processorConstructor.newInstance(this.executor);
} catch (NoSuchMethodException e1) {
// To the next step...
try {
if(selectorProvider==null) {
processorConstructor = processorType.getConstructor(Executor.class);
pool[0] = processorConstructor.newInstance(this.executor);
} else {
processorConstructor = processorType.getConstructor(Executor.class, SelectorProvider.class);
pool[0] = processorConstructor.newInstance(this.executor,selectorProvider);
}
} catch (NoSuchMethodException e2) {
// To the next step...
try {
processorConstructor = processorType.getConstructor();
usesExecutorArg = false;
pool[0] = processorConstructor.newInstance();
} catch (NoSuchMethodException e3) {
// To the next step...
}
}
}
} catch (RuntimeException re) {
LOGGER.error("Cannot create an IoProcessor :{}", re.getMessage());
throw re;
} catch (Exception e) {
String msg = "Failed to create a new instance of " + processorType.getName() + ":" + e.getMessage();
LOGGER.error(msg, e);
throw new RuntimeIoException(msg, e);
}
//根据CPU数量来创建线程池中线程数量.默认最小为一个
// Constructor found now use it for all subsequent instantiations
for (int i = 1; i < pool.length; i++)
{
try {
if (usesExecutorArg) {
if(selectorProvider==null) {
pool[i] = processorConstructor.newInstance(this.executor);
} else {
pool[i] = processorConstructor.newInstance(this.executor, selectorProvider);
}
} else {
pool[i] = processorConstructor.newInstance();
}
} catch (Exception e) {
// Won't happen because it has been done previously
}
}
success = true;
} finally {
if (!success) {
dispose();
}
}
}
到此为止,Apache mina线程模型已经清晰。在创建 NioSocketAcceptor acceptor = new NioSocketAcceptor(); 并且绑定端口时,创建一个Acceptor线程用来接收新socket。
同时创建N个IoProcess用于处理IO操作。IoProcess线程默认数量为机器CPU数量+1.
每一个IoSession根据ID与线程池中索引顺序来关联。每一个IoSession有且只有一个关联的Process.
private void startupAcceptor() throws InterruptedException
{
if (!selectable)
{
registerQueue.clear();
cancelQueue.clear();
}
// start the acceptor if not already started
Acceptor acceptor = acceptorRef.get();
if (acceptor == null)
{
lock.acquire();
acceptor = new Acceptor();
if (acceptorRef.compareAndSet(null, acceptor))
{
executeWorker(acceptor); //Acceptor线程在这里执行
}
else
{
lock.release();
}
}
}
protected final void executeWorker(Runnable worker, String suffix)
{
String actualThreadName = threadName;
if (suffix != null)
{
actualThreadName = actualThreadName + '-' + suffix;
}
executor.execute(new NamePreservingRunnable(worker, actualThreadName)); //Acceptor为保存线程名称类,用来接收新socket接入
}
内部类Acceptor为处理新socket链接的主要类,代码如下:
/**
* This class is called by the startupAcceptor() method and is
* placed into a NamePreservingRunnable class.
* It's a thread accepting incoming connections from clients.
* The loop is stopped when all the bound handlers are unbound.
*/
//Acceptor类在AbstractIoAcceptor中用来启动Acceptor,一个NamePreseringRunnable类.
//Acceptor用来处理新socket的链接。、
//无限循环执行来判断是否有新socket链接进来
private class Acceptor implements Runnable
{
public void run()
{
assert (acceptorRef.get() == this);
//新socket的数量
int nHandles = 0;
//Acceptor类是一个NamePreservingRunable 类,用来处理新链接的socket
// Release the lock
lock.release();
while (selectable)
{
try
{
// Detect if we have some keys ready to be processed
// The select() will be woke up if some new connection
// have occurred, or if the selector has been explicitly
// woke up
//Acceptor执行select()函数来判断是否有新的链接进入socket
//阻塞函数,当select()返回时,有新socket进入
int selected = select();
// this actually sets the selector to OP_ACCEPT,
// and binds to the port on which this class will
// listen on
nHandles += registerHandles();
// Now, if the number of registred handles is 0, we can
// quit the loop: we don't have any socket listening
// for incoming connection.
if (nHandles == 0)
{
acceptorRef.set(null);
if (registerQueue.isEmpty() && cancelQueue.isEmpty())
{
assert (acceptorRef.get() != this);
break;
}
if (!acceptorRef.compareAndSet(null, this)) {
assert (acceptorRef.get() != this);
break;
}
assert (acceptorRef.get() == this);
}
if (selected > 0)
{
// We have some connection request, let's process
// them here.
//当select()函数执行完后,发现有新的socket进入.
//selected数量来判断新进入的socket,并且初始化IoSession和IoProcess相关联。一个socket有且只与一个socket相关联
processHandles(selectedHandles());
}
// check to see if any cancellation request has been made.
nHandles -= unregisterHandles();
} catch (ClosedSelectorException cse) {
// If the selector has been closed, we can exit the loop
ExceptionMonitor.getInstance().exceptionCaught(cse);
break;
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
ExceptionMonitor.getInstance().exceptionCaught(e1);
}
}
}
//
// 总结: 1、IoAcceptor线程,来处理接入的socket 然后,使IoSession和IoProcess相关联。多个IoProcess处理IoSession.但是一个IoSession仅仅对应一个IoProcess.并且IoAcceptor的线程数量为1.
// 2、 IoPross线程。在SimpleIoProcessorPool中配置。 private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;
// IoProcess线程数量默认设置为Mina内置配置。
// 3、 IoHandler 逻辑处理和IoProcess IO线程是同一个线程。如果,IoHandler线程阻塞,将影响IO操作。同时,影响与该IoProcess相关联的所有IoSession.
// 4、如果IoHandler会阻塞IoProcess线程,那么可以通过
//
/以上代码是Acceptor来处理新链接的socket//
// Cleanup all the processors, and shutdown the acceptor.
if (selectable && isDisposing())
{
selectable = false;
try {
if (createdProcessor) {
processor.dispose();
}
} finally {
try {
synchronized (disposalLock) {
if (isDisposing()) {
destroy();
}
}
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
} finally {
disposalFuture.setDone();
}
}
}
}