Explicit thread group on DefaultThreadFactory.

Motivation:

Fixes #5084. We (gRPC) encountered a bug that was triggered by
grpc/grpc-java@d927180. After that commit, event loop threads are
created per task by NioEventLoopGroup, and inherits the thread group of
the caller, which in our case is an application-provided request-scope
thread. Things go south when the application tries to manipulate (e.g.,
interrupt and join) all threads of the request-scope thread group, which
unexpectedly include the event loop threads.

Modifications:

DefaultThreadFactory will save the current thread group in constructor,
and apply it to all new threads.

Result:

Threads created by DefaultThreadFactory will be in the same thread group
as the thread where the factory is created.
This commit is contained in:
Kun Zhang 2016-04-05 20:43:34 -07:00 committed by Norman Maurer
parent 66ce014074
commit 8bdf73edea

View File

@ -16,6 +16,7 @@
package io.netty.util.concurrent; package io.netty.util.concurrent;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import java.util.Locale; import java.util.Locale;
@ -33,6 +34,7 @@ public class DefaultThreadFactory implements ThreadFactory {
private final String prefix; private final String prefix;
private final boolean daemon; private final boolean daemon;
private final int priority; private final int priority;
private final ThreadGroup threadGroup;
public DefaultThreadFactory(Class<?> poolType) { public DefaultThreadFactory(Class<?> poolType) {
this(poolType, false, Thread.NORM_PRIORITY); this(poolType, false, Thread.NORM_PRIORITY);
@ -82,7 +84,7 @@ public class DefaultThreadFactory implements ThreadFactory {
} }
} }
public DefaultThreadFactory(String poolName, boolean daemon, int priority) { public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
if (poolName == null) { if (poolName == null) {
throw new NullPointerException("poolName"); throw new NullPointerException("poolName");
} }
@ -94,6 +96,11 @@ public class DefaultThreadFactory implements ThreadFactory {
prefix = poolName + '-' + poolId.incrementAndGet() + '-'; prefix = poolName + '-' + poolId.incrementAndGet() + '-';
this.daemon = daemon; this.daemon = daemon;
this.priority = priority; this.priority = priority;
this.threadGroup = ObjectUtil.checkNotNull(threadGroup, "threadGroup");
}
public DefaultThreadFactory(String poolName, boolean daemon, int priority) {
this(poolName, daemon, priority, Thread.currentThread().getThreadGroup());
} }
@Override @Override
@ -119,8 +126,9 @@ public class DefaultThreadFactory implements ThreadFactory {
return t; return t;
} }
// TODO: Once we can break the API we should add ThreadGroup to the arguments of this method.
protected Thread newThread(Runnable r, String name) { protected Thread newThread(Runnable r, String name) {
return new FastThreadLocalThread(r, name); return new FastThreadLocalThread(threadGroup, r, name);
} }
private static final class DefaultRunnableDecorator implements Runnable { private static final class DefaultRunnableDecorator implements Runnable {