回顾

在上一节,我尝试追踪NioEventLoopGroup的构造函数,然后经历了一层层套娃,最终到达了MultithreadEventExecutorGroup的一个构造函数中,下面再贴一次代码+坐标:

此处【坐标1】

这节要讲的就是new ThreadPerTaskExecutor这个构造函数。

  • new ThreadPerTaskExecutor - 创建NioEventLoop执行任务线程的线程执行器。

Netty Version: 4.1.6


ThreadPerTaskExcutor

首先起点就是上面的【坐标1】构造方法,然后先进入ThreadPerTaskExecutor的构造方法看看:

  • 将threadFactory实例保存下来了。
  • execute方法每接到一个任务都会开辟新的线程去执行

那么这个threadFactory到底是啥呢?它的newThread返回的又是什么线程?线程的命名规则又是如何?不急,接着走下去就知道答案了。

先将视角切回本篇【坐标1】,我们进入newDefaultThreadFactory(),此处【坐标3】:
io.netty.util.concurrent.MultithreadEventExecutorGroup#newDefaultThreadFactory

java
  • 01
  • 02
  • 03
protected ThreadFactory newDefaultThreadFactory() { return new DefaultThreadFactory(getClass()); }
  • 这里的getClass()就是NioEventLoopGroup,等下去到命名规则就揭晓了。

继续,进入new DefaultThreadFactory:
io.netty.util.concurrent.DefaultThreadFactory#DefaultThreadFactory(java.lang.Class<?>)

java
  • 01
  • 02
  • 03
public DefaultThreadFactory(Class<?> poolType) { this(poolType, false, Thread.NORM_PRIORITY); }

继续,进入this,此处【坐标2】:
io.netty.util.concurrent.DefaultThreadFactory#DefaultThreadFactory(java.lang.Class<?>, boolean, int)

java
  • 01
  • 02
  • 03
public DefaultThreadFactory(Class<?> poolType, boolean daemon, int priority) { this(toPoolName(poolType), daemon, priority); }

来到这里我们先不急着继续进入this,可以看看toPoolName方法,它就是给线程起名字前缀的:
io.netty.util.concurrent.DefaultThreadFactory#DefaultThreadFactory(java.lang.Class<?>, boolean, int)

  • 可以证实,之前的getClass()就是NioEventLoopGroup。
  • 转换之后返回nioEventLoopGroup(其实就是头字母变小写)

现在,视角再切回【坐标2】,继续进入this:
io.netty.util.concurrent.DefaultThreadFactory#DefaultThreadFactory(java.lang.String, boolean, int)

java
  • 01
  • 02
  • 03
  • 04
public DefaultThreadFactory(String poolName, boolean daemon, int priority) { this(poolName, daemon, priority, System.getSecurityManager() == null ? Thread.currentThread().getThreadGroup() : System.getSecurityManager().getThreadGroup()); }

继续,进入this:
io.netty.util.concurrent.DefaultThreadFactory#DefaultThreadFactory(java.lang.String, boolean, int, java.lang.ThreadGroup)

java
  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) { if (poolName == null) { throw new NullPointerException("poolName"); } if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { throw new IllegalArgumentException( "priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)"); } prefix = poolName + '-' + poolId.incrementAndGet() + '-'; this.daemon = daemon; this.priority = priority; this.threadGroup = threadGroup; }
  • 到此完成构造。
  • 线程命名前缀为nioEventLoopGroup-poolId-,poolId类型是AtomicInteger(提供线程安全操作),每次设置前缀时都会自增1。


上面看完构造函数之后不用急着离开,因为当前类还有个核心的方法,即上面【坐标3】的newThred方法就在这个类中,我们来看一下:

io.netty.util.concurrent.DefaultThreadFactory#newThread(java.lang.Runnable)

java
  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
public Thread newThread(Runnable r) { Thread t = newThread(new DefaultRunnableDecorator(r), prefix + nextId.incrementAndGet()); try { if (t.isDaemon()) { if (!daemon) { t.setDaemon(false); } } else { if (daemon) { t.setDaemon(true); } } if (t.getPriority() != priority) { t.setPriority(priority); } } catch (Exception ignored) { // Doesn't matter even if failed to set. } return t; }
  • 这个newThread会在之后的这篇中用到
  • 这个newThread中的核心方法也叫newThread。
  • 并且这里能得到完整的线程名称,即nioEventLoopGroup-prefix-nextId。

继续,进入newThread方法:
io.netty.util.concurrent.DefaultThreadFactory#newThread(java.lang.Runnable, java.lang.String)

java
  • 01
  • 02
  • 03
protected Thread newThread(Runnable r, String name) { return new FastThreadLocalThread(threadGroup, r, name); }
  • 可以发现这里其实new了一个FastThreadLocalThread,它是经过Netty封装的一个类。

关于FastThreadLocalThread据说是做了一些优化,至于是怎么优化的先不探究,这里就简单看下类关系图:



小结

  • new ThreadPerTaskExecutor就是给返回一个线程的创建器,NioEventLoop可以把接受到的任务通过创建器的execute方法(execute又调用new Thread)创建FastThreadLocalThread线程执行任务。
  • 另外,我们还知道了NioEventLoopGroup线程的命名规则:nioEventLoopGroup-prefix-nextId。其中prefix、nextId都会自增。