org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory Maven / Gradle / Ivy
Show all versions of netty Show documentation
/*
* 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 org.jboss.netty.channel.socket.oio;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.SocketChannel;
import org.jboss.netty.util.ThreadNameDeterminer;
import org.jboss.netty.util.internal.ExecutorUtil;
/**
* A {@link ClientSocketChannelFactory} which creates a client-side blocking
* I/O based {@link SocketChannel}. It utilizes the good old blocking I/O API
* which is known to yield better throughput and latency when there are
* relatively small number of connections to serve.
*
* How threads work
*
* There is only one type of threads in {@link OioClientSocketChannelFactory};
* worker threads.
*
*
Worker threads
*
* Each connected {@link Channel} has a dedicated worker thread, just like a
* traditional blocking I/O thread model.
*
*
Life cycle of threads and graceful shutdown
*
* Worker threads are acquired from the {@link Executor} which was specified
* when a {@link OioClientSocketChannelFactory} was created (i.e. {@code workerExecutor}.)
* Therefore, you should make sure the specified {@link Executor} is able to
* lend the sufficient number of threads.
*
* Worker threads are acquired lazily, and then released when there's nothing
* left to process. All the related resources are also released when the
* worker threads are released. Therefore, to shut down a service gracefully,
* you should do the following:
*
*
* - close all channels created by the factory usually using
* {@link ChannelGroup#close()}, and
* - call {@link #releaseExternalResources()}.
*
*
* Please make sure not to shut down the executor until all channels are
* closed. Otherwise, you will end up with a {@link RejectedExecutionException}
* and the related resources might not be released properly.
*
* Limitation
*
* A {@link SocketChannel} created by this factory does not support asynchronous
* operations. Any I/O requests such as {@code "connect"} and {@code "write"}
* will be performed in a blocking manner.
*
* @apiviz.landmark
*/
public class OioClientSocketChannelFactory implements ClientSocketChannelFactory {
private final Executor workerExecutor;
final OioClientSocketPipelineSink sink;
private boolean shutdownExecutor;
/**
* Creates a new instance with a {@link Executors#newCachedThreadPool()} as worker executor.
*
* See {@link #OioClientSocketChannelFactory(Executor)}
*/
public OioClientSocketChannelFactory() {
this(Executors.newCachedThreadPool());
shutdownExecutor = true;
}
/**
* Creates a new instance.
*
* @param workerExecutor
* the {@link Executor} which will execute the I/O worker threads
*/
public OioClientSocketChannelFactory(Executor workerExecutor) {
this(workerExecutor, null);
}
/**
* Creates a new instance.
*
* @param workerExecutor
* the {@link Executor} which will execute the I/O worker threads
* @param determiner
* the {@link ThreadNameDeterminer} to set the thread names.
*/
public OioClientSocketChannelFactory(Executor workerExecutor,
ThreadNameDeterminer determiner) {
if (workerExecutor == null) {
throw new NullPointerException("workerExecutor");
}
this.workerExecutor = workerExecutor;
sink = new OioClientSocketPipelineSink(workerExecutor, determiner);
}
public SocketChannel newChannel(ChannelPipeline pipeline) {
return new OioClientSocketChannel(this, pipeline, sink);
}
public void shutdown() {
if (shutdownExecutor) {
ExecutorUtil.shutdownNow(workerExecutor);
}
}
public void releaseExternalResources() {
shutdown();
ExecutorUtil.shutdownNow(workerExecutor);
}
}