Add MultithreadEventLoopGroup.DEFAULT_EVENT_LOOP_THREADS / Add DefaultThreadFactory

- Allow overriding the default thread factory when a user specified no thread factory
This commit is contained in:
Trustin Lee 2013-04-03 17:49:30 +09:00
parent 312a35dfed
commit 117ad8acd7
6 changed files with 163 additions and 46 deletions

View File

@ -0,0 +1,125 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.concurrent;
import java.util.Locale;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@link ThreadFactory} implementation with a simple naming rule.
*/
public class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolId = new AtomicInteger();
private final AtomicInteger nextId = new AtomicInteger();
private final String prefix;
private final boolean daemon;
private final int priority;
public DefaultThreadFactory(Class<?> poolType) {
this(poolType, false, Thread.NORM_PRIORITY);
}
public DefaultThreadFactory(String poolName) {
this(poolName, false, Thread.NORM_PRIORITY);
}
public DefaultThreadFactory(Class<?> poolType, boolean daemon) {
this(poolType, daemon, Thread.NORM_PRIORITY);
}
public DefaultThreadFactory(String poolName, boolean daemon) {
this(poolName, daemon, Thread.NORM_PRIORITY);
}
public DefaultThreadFactory(Class<?> poolType, int priority) {
this(poolType, false, priority);
}
public DefaultThreadFactory(String poolName, int priority) {
this(poolName, false, priority);
}
public DefaultThreadFactory(Class<?> poolType, boolean daemon, int priority) {
this(toPoolName(poolType), daemon, priority);
}
private static String toPoolName(Class<?> poolType) {
if (poolType == null) {
throw new NullPointerException("poolType");
}
String poolName;
Package pkg = poolType.getPackage();
if (pkg != null) {
poolName = poolType.getName().substring(pkg.getName().length() + 1);
} else {
poolName = poolType.getName();
}
switch (poolName.length()) {
case 0:
return "unknown";
case 1:
return poolName.toLowerCase(Locale.US);
default:
if (Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))) {
return Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1);
} else {
return poolName;
}
}
}
public DefaultThreadFactory(String poolName, boolean daemon, int priority) {
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;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(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;
}
}

View File

@ -28,8 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
private static final AtomicInteger poolId = new AtomicInteger();
private final EventExecutor[] children;
private final AtomicInteger childIndex = new AtomicInteger();
@ -46,7 +44,7 @@ public abstract class MultithreadEventExecutorGroup extends AbstractEventExecuto
}
if (threadFactory == null) {
threadFactory = new DefaultThreadFactory();
threadFactory = newDefaultThreadFactory();
}
children = new SingleThreadEventExecutor[nThreads];
@ -68,6 +66,10 @@ public abstract class MultithreadEventExecutorGroup extends AbstractEventExecuto
}
}
protected ThreadFactory newDefaultThreadFactory() {
return new DefaultThreadFactory(getClass());
}
@Override
public EventExecutor next() {
return children[Math.abs(childIndex.getAndIncrement() % children.length)];
@ -138,31 +140,4 @@ public abstract class MultithreadEventExecutorGroup extends AbstractEventExecuto
}
return isTerminated();
}
private final class DefaultThreadFactory implements ThreadFactory {
private final AtomicInteger nextId = new AtomicInteger();
private final String prefix;
DefaultThreadFactory() {
String typeName = MultithreadEventExecutorGroup.this.getClass().getSimpleName();
typeName = Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1);
prefix = typeName + '-' + poolId.incrementAndGet() + '-';
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, prefix + nextId.incrementAndGet());
try {
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.MAX_PRIORITY) {
t.setPriority(Thread.MAX_PRIORITY);
}
} catch (Exception ignored) {
// Doesn't matter even if failed to set.
}
return t;
}
}
}

View File

@ -15,7 +15,11 @@
*/
package io.netty.channel;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.MultithreadEventExecutorGroup;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.util.concurrent.ThreadFactory;
@ -25,13 +29,28 @@ import java.util.concurrent.ThreadFactory;
*/
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
/**
* @see {@link MultithreadEventExecutorGroup##MultithreadEventLoopGroup(int,ThreadFactory, Object...)}
*/
private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);
public static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
if (logger.isDebugEnabled()) {
logger.debug("io.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
}
}
protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
super(nThreads, threadFactory, args);
}
@Override
protected ThreadFactory newDefaultThreadFactory() {
return new DefaultThreadFactory(getClass(), Thread.MAX_PRIORITY);
}
@Override
public EventLoop next() {
return (EventLoop) super.next();

View File

@ -42,17 +42,16 @@ public class AioEventLoopGroup extends MultithreadEventLoopGroup {
}
/**
* Create a new instance which use the default number of threads of {@link #DEFAULT_POOL_SIZE}.
* Create a new instance which use the default number of threads of {@link #DEFAULT_EVENT_LOOP_THREADS}.
*/
public AioEventLoopGroup() {
this(0);
this(DEFAULT_EVENT_LOOP_THREADS);
}
/**
* Create a new instance
*
* @param nThreads the number of threads that will be used by this instance. Use 0 for the default number
* of {@link #DEFAULT_POOL_SIZE}
* @param nThreads the number of threads that will be used by this instance
*/
public AioEventLoopGroup(int nThreads) {
this(nThreads, null);
@ -61,8 +60,7 @@ public class AioEventLoopGroup extends MultithreadEventLoopGroup {
/**
* Create a new instance.
*
* @param nThreads the number of threads that will be used by this instance. Use 0 for the default number
* of {@link #DEFAULT_POOL_SIZE}
* @param nThreads the number of threads that will be used by this instance
* @param threadFactory the ThreadFactory to use, or {@code null} if the default should be used.
*/
public AioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {

View File

@ -26,16 +26,16 @@ import java.util.concurrent.ThreadFactory;
public class LocalEventLoopGroup extends MultithreadEventLoopGroup {
/**
* Create a new instance which used {@link #DEFAULT_POOL_SIZE} number of Threads
* Create a new instance which used {@link #DEFAULT_EVENT_LOOP_THREADS} number of Threads
*/
public LocalEventLoopGroup() {
this(0);
this(DEFAULT_EVENT_LOOP_THREADS);
}
/**
* Create a new instance
*
* @param nThreads the number of Threads to use or {@code 0} for the default of {@link #DEFAULT_POOL_SIZE}
* @param nThreads the number of threads to use
*/
public LocalEventLoopGroup(int nThreads) {
this(nThreads, null);
@ -44,7 +44,7 @@ public class LocalEventLoopGroup extends MultithreadEventLoopGroup {
/**
* Create a new instance
*
* @param nThreads the number of Threads to use or {@code 0} for the default of {@link #DEFAULT_POOL_SIZE}
* @param nThreads the number of threads to use
* @param threadFactory the {@link ThreadFactory} or {@code null} to use the default
*/
public LocalEventLoopGroup(int nThreads, ThreadFactory threadFactory) {

View File

@ -29,11 +29,11 @@ import java.util.concurrent.ThreadFactory;
public class NioEventLoopGroup extends MultithreadEventLoopGroup {
/**
* Create a new instance using {@link #DEFAULT_POOL_SIZE} number of threads, the default {@link ThreadFactory} and
* the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
* Create a new instance using {@link #DEFAULT_EVENT_LOOP_THREADS} number of threads, the default
* {@link ThreadFactory} and the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
*/
public NioEventLoopGroup() {
this(0);
this(DEFAULT_EVENT_LOOP_THREADS);
}
/**