netty5/transport/src/main/java/io/netty/channel/ThreadPerChannelEventLoop.java
Trustin Lee 23d0178494 Introduce EventExecutor.shutdownGracefully() that deprecates shutdown()
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
2013-05-01 10:52:38 +09:00

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