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.
This commit is contained in:
Norman Maurer 2015-08-25 12:20:23 +02:00
parent 01c29e5cc7
commit 63014fe118
3 changed files with 180 additions and 1 deletions

View File

@ -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<Runnable> taskQueue;
private final Thread thread;
private final ThreadProperties threadProperties;
private final Semaphore threadLock = new Semaphore(0);
private final Set<Runnable> shutdownHooks = new LinkedHashSet<Runnable>();
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();
}
}
}

View File

@ -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();
}

View File

@ -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<Thread> threadRef = new AtomicReference<Thread>();
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();
}
}