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:
parent
68b5232d74
commit
544ee95e58
@ -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;
|
||||
@ -54,9 +55,16 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
private static final Runnable NOOP_TASK = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
|
||||
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER;
|
||||
private static final AtomicReferenceFieldUpdater<SingleThreadEventExecutor, Thread> THREAD_UPDATER;
|
||||
private static final AtomicReferenceFieldUpdater<SingleThreadEventExecutor, ThreadProperties> PROPERTIES_UPDATER;
|
||||
|
||||
static {
|
||||
AtomicIntegerFieldUpdater<SingleThreadEventExecutor> updater =
|
||||
@ -73,12 +81,20 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx
|
||||
SingleThreadEventExecutor.class, Thread.class, "thread");
|
||||
}
|
||||
THREAD_UPDATER = refUpdater;
|
||||
AtomicReferenceFieldUpdater<SingleThreadEventExecutor, ThreadProperties> propertiesUpdater =
|
||||
PlatformDependent.newAtomicReferenceFieldUpdater(SingleThreadEventExecutor.class, "threadProperties");
|
||||
if (propertiesUpdater == null) {
|
||||
propertiesUpdater = AtomicReferenceFieldUpdater.newUpdater(SingleThreadEventExecutor.class,
|
||||
ThreadProperties.class, "threadProperties");
|
||||
}
|
||||
PROPERTIES_UPDATER = propertiesUpdater;
|
||||
}
|
||||
|
||||
private final Queue<Runnable> taskQueue;
|
||||
|
||||
@SuppressWarnings({ "FieldMayBeFinal", "unused" })
|
||||
private volatile Thread thread;
|
||||
private volatile ThreadProperties threadProperties;
|
||||
private final Executor executor;
|
||||
private final Semaphore threadLock = new Semaphore(0);
|
||||
private final Set<Runnable> shutdownHooks = new LinkedHashSet<Runnable>();
|
||||
@ -668,6 +684,31 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ThreadProperties} of the {@link Thread} that powers the {@link SingleThreadEventExecutor}.
|
||||
* If the {@link SingleThreadEventExecutor} is not started yet, this operation will start it and block until the
|
||||
* it is fully started.
|
||||
*/
|
||||
public final ThreadProperties threadProperties() {
|
||||
ThreadProperties threadProperties = this.threadProperties;
|
||||
if (threadProperties == null) {
|
||||
Thread thread = this.thread;
|
||||
if (thread == null) {
|
||||
assert !inEventLoop();
|
||||
submit(NOOP_TASK).syncUninterruptibly();
|
||||
thread = this.thread;
|
||||
assert thread != null;
|
||||
}
|
||||
|
||||
threadProperties = new DefaultThreadProperties(thread);
|
||||
if (!PROPERTIES_UPDATER.compareAndSet(this, null, threadProperties)) {
|
||||
threadProperties = this.threadProperties;
|
||||
}
|
||||
}
|
||||
|
||||
return threadProperties;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected boolean wakesUpForTask(Runnable task) {
|
||||
return true;
|
||||
@ -738,4 +779,52 @@ public abstract class SingleThreadEventExecutor extends AbstractScheduledEventEx
|
||||
private void updateThread(Thread t) {
|
||||
THREAD_UPDATER.lazySet(this, t);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.Executors;
|
||||
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, Executors.newCachedThreadPool(), false) {
|
||||
@Override
|
||||
protected void run() {
|
||||
threadRef.set(Thread.currentThread());
|
||||
while (!confirmShutdown()) {
|
||||
Runnable task = takeTask();
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user