23d0178494
shutdownGracefully() provides two optional parameters that give more control over when an executor has to be shut down. - Related issue: #1307 - Add shutdownGracefully(..) and isShuttingDown() - Deprecate shutdown() / shutdownNow() - Replace lastAccessTime with lastExecutionTime and update it after task execution for accurate quiet period check - runAllTasks() and runShutdownTasks() update it automatically. - Add updateLastExecutionTime() so that subclasses can update it - Add a constructor parameter that tells not to add an unncessary wakeup task in execute() if addTask() wakes up the executor thread automatically. Previously, execute() always called wakeup() after addTask(), which often caused an extra dummy task in the task queue. - Use shutdownGracefully() wherever possible / Deprecation javadoc - Reduce the running time of SingleThreadEventLoopTest from 40s to 15s using custom graceful shutdown parameters - Other changes made along with this commit: - takeTask() does not throw InterruptedException anymore. - Returns null on interruption or wakeup - Make sure runShutdownTasks() return true even if an exception was raised while running the shutdown tasks - Remove unnecessary isShutdown() checks - Consistent use of SingleThreadEventExecutor.nanoTime() Replace isWakeupOverridden with a constructor parameter
83 lines
2.6 KiB
Java
83 lines
2.6 KiB
Java
/*
|
|
* Copyright 2012 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.channel;
|
|
|
|
/**
|
|
* {@link SingleThreadEventLoop} which is used to handle OIO {@link Channel}'s. So in general there will be
|
|
* one {@link ThreadPerChannelEventLoop} per {@link Channel}.
|
|
*
|
|
*/
|
|
public class ThreadPerChannelEventLoop extends SingleThreadEventLoop {
|
|
|
|
private final ThreadPerChannelEventLoopGroup parent;
|
|
private Channel ch;
|
|
|
|
public ThreadPerChannelEventLoop(ThreadPerChannelEventLoopGroup parent) {
|
|
super(parent, parent.threadFactory, true);
|
|
this.parent = parent;
|
|
}
|
|
|
|
@Override
|
|
public ChannelFuture register(Channel channel, ChannelPromise promise) {
|
|
return super.register(channel, promise).addListener(new ChannelFutureListener() {
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
public void operationComplete(ChannelFuture future) throws Exception {
|
|
if (future.isSuccess()) {
|
|
ch = future.channel();
|
|
} else {
|
|
deregister();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected void run() {
|
|
for (;;) {
|
|
Runnable task = takeTask();
|
|
if (task != null) {
|
|
task.run();
|
|
updateLastExecutionTime();
|
|
}
|
|
|
|
Channel ch = this.ch;
|
|
if (isShuttingDown()) {
|
|
if (ch != null) {
|
|
ch.unsafe().close(ch.unsafe().voidFuture());
|
|
}
|
|
if (confirmShutdown()) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (ch != null) {
|
|
// Handle deregistration
|
|
if (!ch.isRegistered()) {
|
|
runAllTasks();
|
|
deregister();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void deregister() {
|
|
ch = null;
|
|
parent.activeChildren.remove(this);
|
|
parent.idleChildren.add(this);
|
|
}
|
|
}
|