From 63014fe118f348c20b40e08f109ee8cc333aad8c Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Tue, 25 Aug 2015 12:20:23 +0200 Subject: [PATCH] Allow to get details of the Thread that powers a SingleThreadEventExecutor. Motivation: for debugging and metrics reasons its sometimes useful to be able to get details of the the Thread that powers a SingleThreadEventExecutor. Modifications: - Expose ThreadProperties - Add unit test. Result: It's now possible to get details of the Thread that powers a SingleThreadEventExecutor. --- .../concurrent/SingleThreadEventExecutor.java | 59 +++++++++++++++++- .../util/concurrent/ThreadProperties.java | 61 +++++++++++++++++++ .../SingleThreadEventExecutorTest.java | 61 +++++++++++++++++++ 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/io/netty/util/concurrent/ThreadProperties.java create mode 100644 common/src/test/java/io/netty/util/concurrent/SingleThreadEventExecutorTest.java diff --git a/common/src/main/java/io/netty/util/concurrent/SingleThreadEventExecutor.java b/common/src/main/java/io/netty/util/concurrent/SingleThreadEventExecutor.java index 8e8e9d1139..1633f4c08d 100644 --- a/common/src/main/java/io/netty/util/concurrent/SingleThreadEventExecutor.java +++ b/common/src/main/java/io/netty/util/concurrent/SingleThreadEventExecutor.java @@ -19,6 +19,7 @@ import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import java.lang.Thread.State; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -68,6 +69,7 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx private final EventExecutorGroup parent; private final Queue taskQueue; private final Thread thread; + private final ThreadProperties threadProperties; private final Semaphore threadLock = new Semaphore(0); private final Set shutdownHooks = new LinkedHashSet(); private final boolean addTaskWakesUp; @@ -152,7 +154,7 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx } } }); - + threadProperties = new DefaultThreadProperties(thread); taskQueue = newTaskQueue(); } @@ -697,6 +699,13 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx } } + /** + * Returns the {@link ThreadProperties} of the {@link Thread} that powers the {@link SingleThreadEventExecutor}. + */ + public final ThreadProperties threadProperties() { + return threadProperties; + } + @SuppressWarnings("unused") protected boolean wakesUpForTask(Runnable task) { return true; @@ -717,4 +726,52 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx } } } + + private static final class DefaultThreadProperties implements ThreadProperties { + private final Thread t; + + DefaultThreadProperties(Thread t) { + this.t = t; + } + + @Override + public State state() { + return t.getState(); + } + + @Override + public int priority() { + return t.getPriority(); + } + + @Override + public boolean isInterrupted() { + return t.isInterrupted(); + } + + @Override + public boolean isDaemon() { + return t.isDaemon(); + } + + @Override + public String name() { + return t.getName(); + } + + @Override + public long id() { + return t.getId(); + } + + @Override + public StackTraceElement[] stackTrace() { + return t.getStackTrace(); + } + + @Override + public boolean isAlive() { + return t.isAlive(); + } + } } diff --git a/common/src/main/java/io/netty/util/concurrent/ThreadProperties.java b/common/src/main/java/io/netty/util/concurrent/ThreadProperties.java new file mode 100644 index 0000000000..b814b5ffea --- /dev/null +++ b/common/src/main/java/io/netty/util/concurrent/ThreadProperties.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015 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; + +/** + * Expose details for a {@link Thread}. + */ +public interface ThreadProperties { + /** + * @see {@link Thread#getState()}. + */ + Thread.State state(); + + /** + * @see {@link Thread#getPriority()}. + */ + int priority(); + + /** + * @see {@link Thread#isInterrupted()}. + */ + boolean isInterrupted(); + + /** + * @see {@link Thread#isDaemon()} ()}. + */ + boolean isDaemon(); + + /** + * @see {@link Thread#getName()} ()}. + */ + String name(); + + /** + * @see {@link Thread#getId()}. + */ + long id(); + + /** + * @see {@link Thread#getStackTrace()}. + */ + StackTraceElement[] stackTrace(); + + /** + * @see {@link Thread#isAlive()}. + */ + boolean isAlive(); +} diff --git a/common/src/test/java/io/netty/util/concurrent/SingleThreadEventExecutorTest.java b/common/src/test/java/io/netty/util/concurrent/SingleThreadEventExecutorTest.java new file mode 100644 index 0000000000..1cc59bf084 --- /dev/null +++ b/common/src/test/java/io/netty/util/concurrent/SingleThreadEventExecutorTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015 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 org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicReference; + +public class SingleThreadEventExecutorTest { + + @Test + public void testThreadDetails() { + final AtomicReference threadRef = new AtomicReference(); + SingleThreadEventExecutor executor = new SingleThreadEventExecutor( + null, new DefaultThreadFactory("test"), false) { + @Override + protected void run() { + threadRef.set(Thread.currentThread()); + while (!confirmShutdown()) { + Runnable task = takeTask(); + if (task != null) { + task.run(); + } + } + } + }; + executor.submit(new Runnable() { + @Override + public void run() { + // NOOP + } + }).syncUninterruptibly(); + ThreadProperties threadProperties = executor.threadProperties(); + Assert.assertSame(threadProperties, executor.threadProperties()); + + Thread thread = threadRef.get(); + Assert.assertEquals(thread.getId(), threadProperties.id()); + Assert.assertEquals(thread.getName(), threadProperties.name()); + Assert.assertEquals(thread.getPriority(), threadProperties.priority()); + Assert.assertEquals(thread.getState(), threadProperties.state()); + Assert.assertEquals(thread.isAlive(), threadProperties.isAlive()); + Assert.assertEquals(thread.isDaemon(), threadProperties.isDaemon()); + Assert.assertEquals(thread.isInterrupted(), threadProperties.isInterrupted()); + Assert.assertTrue(threadProperties.stackTrace().length > 0); + executor.shutdownGracefully(); + } +}