NioEventLoopGroup的创建
服务端一般是通过创建两个NioEventLoopGroup来创建NioEventLoop,一个NioEventLoopGroup主要是用于接收客户端的请求,另外一个NioEventLoopGroup则是处理网络IO的相关读写操作,或者是执行定时任务,或者是系统任务。
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
NioEventLoopGroup的构造函数:
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor)null);
}
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
this(nThreads, threadFactory, SelectorProvider.provider());
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, SelectorProvider selectorProvider) {
this(nThreads, threadFactory, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, SelectorProvider selectorProvider, SelectStrategyFactory selectStrategyFactory) {
super(nThreads, threadFactory, new Object[]{selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()});
}
可以从默认的构造函数看出来,默认传入的线程数是0,默认传入的ThreadFactory是null,并且传入了一个selectorProvider。最后层层调用了父类MultithreadEventLoopGroup的构造函数。
protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
}
这里会判断传入的线程数是不是等于0,如果等于0,就将线程数设置为2*cpu。默认情况下不传参数,会创建2*cpu个线程数的线程池NioEventLoopGroup。然后继续调用父类构造函数该父类的构造函数。
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
this.terminatedChildren = new AtomicInteger();
this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
} else {
if (executor == null) {
executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
}
this.children = new EventExecutor[nThreads];
int j;
for(int i = 0; i < nThreads; ++i) {
boolean success = false;
boolean var18 = false;
try {
var18 = true;
this.children[i] = this.newChild((Executor)executor, args);
success = true;
var18 = false;
} catch (Exception var19) {
throw new IllegalStateException("failed to create a child event loop", var19);
} finally {
if (var18) {
if (!success) {
int j;
for(j = 0; j < i; ++j) {
this.children[j].shutdownGracefully();
}
for(j = 0; j < i; ++j) {
EventExecutor e = this.children[j];
try {
while(!e.isTerminated()) {
e.awaitTermination(2147483647L, TimeUnit.SECONDS);
}
} catch (InterruptedException var20) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
if (!success) {
for(j = 0; j < i; ++j) {
this.children[j].shutdownGracefully();
}
for(j = 0; j < i; ++j) {
EventExecutor e = this.children[j];
try {
while(!e.isTerminated()) {
e.awaitTermination(2147483647L, TimeUnit.SECONDS);
}
} catch (InterruptedException var22) {
Thread.currentThread().interrupt();
break;
}
}
}
}
this.chooser = chooserFactory.newChooser(this.children);
FutureListener<Object> terminationListener = new FutureListener<Object>() {
public void operationComplete(Future<Object> future) throws Exception {
if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
}
}
};
EventExecutor[] var24 = this.children;
j = var24.length;
for(int var26 = 0; var26 < j; ++var26) {
EventExecutor e = var24[var26];
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet(this.children.length);
Collections.addAll(childrenSet, this.children);
this.readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
}
这里的构造函数主要做了三件事情;
1.创建线程构造器ThreadPerTaskExecutor
2.使用newChild方法创建child线程组
3.创建线程选择器
创建线程构造器
这里的ThreadPerTaskExecutor相当于是线程池聚合的一个组件,当线程池需要创建线程时,通过该线程构造器去创建一个线程,线程的创建也是工厂模式的一个应用,每次ThreadPerTaskExecutor.execute()都会调用ThreadFactory的newThread()。
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
} else {
this.threadFactory = threadFactory;
}
}
public void execute(Runnable command) {
this.threadFactory.newThread(command).start();
}
}
而这里传入的threadFactory是一个DefaultThreadFactory。
protected ThreadFactory newDefaultThreadFactory() {
return new DefaultThreadFactory(this.getClass(), 10);
}
DefaultThreadFactory的构造函数:
public DefaultThreadFactory(Class<?> poolType, int priority) {
this((Class)poolType, false, priority);
}
public DefaultThreadFactory(String poolName, boolean daemon) {
this((String)poolName, daemon, 5);
}
public DefaultThreadFactory(Class<?> poolType, int priority) {
this((Class)poolType, false, priority);
}
public DefaultThreadFactory(String poolName, int priority) {
this((String)poolName, false, priority);
}
public DefaultThreadFactory(Class<?> poolType, boolean daemon, int priority) {
this((String)toPoolName(poolType), daemon, priority);
}
private static String toPoolName(Class<?> poolType) {
if(poolType == null) {
throw new NullPointerException("poolType");
} else {
String poolName = StringUtil.simpleClassName(poolType);
switch(poolName.length()) {
case 0:
return "unknown";
case 1:
return poolName.toLowerCase(Locale.US);
default:
return Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))?Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1):poolName;
}
}
}
public DefaultThreadFactory(String poolName, boolean daemon, int priority) {
this.nextId = new AtomicInteger();
if(poolName == null) {
throw new NullPointerException("poolName");
} else if(priority >= 1 && priority <= 10) {
this.prefix = poolName + '-' + poolId.incrementAndGet() + '-';
this.daemon = daemon;
this.priority = priority;
} else {
throw new IllegalArgumentException("priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
}
}
public Thread newThread(Runnable r) {
Thread t = this.newThread(new DefaultThreadFactory.DefaultRunnableDecorator(r), this.prefix + this.nextId.incrementAndGet());
try {
if(t.isDaemon()) {
if(!this.daemon) {
t.setDaemon(false);
}
} else if(this.daemon) {
t.setDaemon(true);
}
if(t.getPriority() != this.priority) {
t.setPriority(this.priority);
}
} catch (Exception var4) {
;
}
return t;
}
这里传入了当前的类类型NioEventLoopGroup,设置当前线程池的名称为nioEventLoopGroup,线程的优先级为5,然后载调用父类构造函数当前线程池的前缀nioEventLoopGroup-线程池id-。
当每次进行newThread的时候,会将线程池前缀和当前的线程数传入,所以线程的名称就为nioEventLoopGroup-线程池id-线程数id。
例如:nioEventLoopGroup-2-1 代表的是第二个线程池的第一个线程。
protected Thread newThread(Runnable r, String name) {
return new FastThreadLocalThread(r, name);
}
当调用newThread方法时,其实创建的是一个FastThreadLocalThread对象,netty底层的一个Thread对象,对Thread进行了包装,优化了相关的ThreadLocal操作。
通过newChild()方法创建NioEventLoop线程组
这里的newChild()方法就是创建一个NioEventLoop。
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider)args[0], ((SelectStrategyFactory)args[1]).newSelectStrategy(), (RejectedExecutionHandler)args[2]);
}
NioEventLoop的构造,要传入父线程池,executor,和provider。每一个NioEventLoop都有一个selector与它进行绑定,为了实现IO多路复用。
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
} else if (strategy == null) {
throw new NullPointerException("selectStrategy");
} else {
this.provider = selectorProvider;
NioEventLoop.SelectorTuple selectorTuple = this.openSelector();
this.selector = selectorTuple.selector;
this.unwrappedSelector = selectorTuple.unwrappedSelector;
this.selectStrategy = strategy;
}
}
调用父类的构造函数。
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
super(parent);
this.threadLock = new Semaphore(0);
this.shutdownHooks = new LinkedHashSet();
this.state = 1;
this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = Math.max(16, maxPendingTasks);
this.executor = (Executor)ObjectUtil.checkNotNull(executor, "executor");
this.taskQueue = this.newTaskQueue(this.maxPendingTasks);
this.rejectedExecutionHandler = (RejectedExecutionHandler)ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
父类创建任务队列,如果不是NioEventLoop对应的线程,当是外部线程时,就将任务放入任务队列,否则使用线程执行任务。这里的任务队列是LinkedBlockingQueue
protected Queue<Runnable> newTaskQueue() {
return new LinkedBlockingQueue();
}
NioEventLoop的主要组件就是selector,taskqueue,thread,selector用于IO多路复用,使用selector才能使得一个线程能处理多个连接(channel的事件),而thread就是存储当前NioEventLoop的线程,如果不在当前线程中,那么就将任务提交到任务队列中taskqueue。
创建线程选择器
线程选择器是对应NioEventLoopGroup.next()方法,每当有一个新的连接进入的时候,NioEventLoopGroup要选择一个NioEventLoop和新连接进行绑定。
在创建线程选择器的时候会判断当前线程池的个数是不是2的幂次方,如果是就创建一个PowerOfTwoEventExecutorChooser,否则就创建一个GenericEventExecutorChooser。
if(isPowerOfTwo(this.children.length)) {
this.chooser = new MultithreadEventExecutorGroup.PowerOfTwoEventExecutorChooser(null);
} else {
this.chooser = new MultithreadEventExecutorGroup.GenericEventExecutorChooser(null);
}
普通的线程选择器:
private final class GenericEventExecutorChooser implements MultithreadEventExecutorGroup.EventExecutorChooser {
private GenericEventExecutorChooser() {
}
public EventExecutor next() {
return MultithreadEventExecutorGroup.this.children[Math.abs(MultithreadEventExecutorGroup.this.childIndex.getAndIncrement() % MultithreadEventExecutorGroup.this.children.length)];
}
}
二的幂次方线程选择器:
private final class PowerOfTwoEventExecutorChooser implements MultithreadEventExecutorGroup.EventExecutorChooser {
private PowerOfTwoEventExecutorChooser() {
}
public EventExecutor next() {
return MultithreadEventExecutorGroup.this.children[MultithreadEventExecutorGroup.this.childIndex.getAndIncrement() & MultithreadEventExecutorGroup.this.children.length - 1];
}
}
但满足线程数是2的幂次方时,采用&操作来优化,&比%要高效很多。