上下文:Netty 3.6.3.Final、Java 1.7、Scala 2.9.x
为了尽量减少(可能空闲的)线程的数量,我想与不同的 NIO 套接字通道工厂(TCP)和一个 NioDatagramChannelFactory 共享 NIO 客户端/服务器和工作池。我正在使用至少两套(或三套 Finagle 堆栈)服务器/客户端引导程序集,每套都有自己的 NIO 套接字通道工厂。为每个老板和工作池使用新的缓存线程池会导致大部分时间不使用的线程负载。粗略的目标是将所有引导程序/通道工厂的工人数量限制为 2 * CPU 核心数,并将老板数限制为 CPU 核心数。
我正在尝试为我自己的一组引导程序切换到 NioServer/ClientBossPool 和 NioWorkerPool。但是根据底层 ThreadPoolExecutor 的配置,关闭引导程序会导致主线程在 AbstractNioSelector 关闭闩锁上永远等待。
class NioClientBossPoolTest {
@Test def shutdown() {
val corePoolSize = 1
val maxPoolSize = Integer.MAX_VALUE
val keepAliveSeconds = 60
val keepAliveUnit = TimeUnit.SECONDS
val blocking = true
val queue: BlockingQueue[Runnable] =
if(blocking) new LinkedBlockingQueue[Runnable](Integer.MAX_VALUE)
else new SynchronousQueue[Runnable]()
val executor = new ThreadPoolExecutor(corePoolSize,
maxPoolSize,
keepAliveSeconds,
keepAliveUnit,
queue)
val clientBossPool = new NioClientBossPool(executor, 1) // B
new NioServerBossPool(executor, 1) // C
val workerPool = new NioWorkerPool(executor, 1) // A
val channelFactory = new NioClientSocketChannelFactory(clientBossPool, workerPool)
val bootstrap = new ClientBootstrap(channelFactory)
// hangs waiting for shutdown latch in AbstractNioSelector (NioWorker or NioClientBoss
// depending on the order of statement A, B, C) for
// LinkedBlockingQueue, corePoolSize = 1 and sequence of statements A, B and C other than [B, A, C]
// LinkedBlockingQueue, corePoolSize = 2 and sequence of statements A, B and C other than
// [A, B, C], [B, C, A] and [C, B, A]
bootstrap.shutdown()
}
}
我很确定执行器服务配置必须满足一些特定要求,但是哪个(核心池大小、队列类型)?bootstrap.shutdown() 将永远阻塞,除非语句 A、B 和 C 的执行顺序正好是 [B, A, C]。对于三个语句的六种组合中的三种,将核心池大小增加到 2 个块。核心池大小 > 2 或 SynchronousQueue 时,每个组合都会终止。