View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.channel.socket.oio;
    17
    18  import java.util.concurrent.Executor;
    19  import java.util.concurrent.Executors;
    20  import java.util.concurrent.RejectedExecutionException;
    21
    22  import org.jboss.netty.channel.Channel;
    23  import org.jboss.netty.channel.ChannelPipeline;
    24  import org.jboss.netty.channel.ChannelSink;
    25  import org.jboss.netty.channel.group.ChannelGroup;
    26  import org.jboss.netty.channel.socket.ServerSocketChannel;
    27  import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
    28  import org.jboss.netty.util.internal.ExecutorUtil;
    29
    30  /**
    31   * A {@link ServerSocketChannelFactory} which creates a server-side blocking
    32   * I/O based {@link ServerSocketChannel}.  It utilizes the good old blocking
    33   * I/O API which is known to yield better throughput and latency when there
    34   * are relatively small number of connections to serve.
    35   *
    36   * <h3>How threads work</h3>
    37   * <p>
    38   * There are two types of threads in a {@link OioServerSocketChannelFactory};
    39   * one is boss thread and the other is worker thread.
    40   *
    41   * <h4>Boss threads</h4>
    42   * <p>
    43   * Each bound {@link ServerSocketChannel} has its own boss thread.
    44   * For example, if you opened two server ports such as 80 and 443, you will
    45   * have two boss threads.  A boss thread accepts incoming connections until
    46   * the port is unbound.  Once a connection is accepted successfully, the boss
    47   * thread passes the accepted {@link Channel} to one of the worker
    48   * threads that the {@link OioServerSocketChannelFactory} manages.
    49   *
    50   * <h4>Worker threads</h4>
    51   * <p>
    52   * Each connected {@link Channel} has a dedicated worker thread, just like a
    53   * traditional blocking I/O thread model.
    54   *
    55   * <h3>Life cycle of threads and graceful shutdown</h3>
    56   * <p>
    57   * All threads are acquired from the {@link Executor}s which were specified
    58   * when a {@link OioServerSocketChannelFactory} was created.  Boss threads are
    59   * acquired from the {@code bossExecutor}, and worker threads are acquired from
    60   * the {@code workerExecutor}.  Therefore, you should make sure the specified
    61   * {@link Executor}s are able to lend the sufficient number of threads.
    62   * <p>
    63   * Both boss and worker threads are acquired lazily, and then released when
    64   * there's nothing left to process.  All the related resources are also
    65   * released when the boss and worker threads are released.  Therefore, to shut
    66   * down a service gracefully, you should do the following:
    67   *
    68   * <ol>
    69   * <li>unbind all channels created by the factory,
    70   * <li>close all child channels accepted by the unbound channels,
    71   *     (these two steps so far is usually done using {@link ChannelGroup#close()})</li>
    72   * <li>call {@link #releaseExternalResources()}.</li>
    73   * </ol>
    74   *
    75   * Please make sure not to shut down the executor until all channels are
    76   * closed.  Otherwise, you will end up with a {@link RejectedExecutionException}
    77   * and the related resources might not be released properly.
    78   *
    79   * <h3>Limitation</h3>
    80   * <p>
    81   * A {@link ServerSocketChannel} created by this factory and its child channels
    82   * do not support asynchronous operations.  Any I/O requests such as
    83   * {@code "write"} will be performed in a blocking manner.
    84   *
    85   * @apiviz.landmark
    86   */
    87  public class OioServerSocketChannelFactory implements ServerSocketChannelFactory {
    88
    89      final Executor bossExecutor;
    90      private final Executor workerExecutor;
    91      private final ChannelSink sink;
    92
    93      /**
    94       * Create a new {@link OioServerSocketChannelFactory} with a {@link Executors#newCachedThreadPool()}
    95       * for the boss and worker executor.
    96       *
    97       * See {@link #OioServerSocketChannelFactory(Executor, Executor)}
    98       */
    99      public OioServerSocketChannelFactory() {
    100         this(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
    101     }
    102
    103     /**
    104      * Creates a new instance.
    105      *
    106      * @param bossExecutor
    107      *        the {@link Executor} which will execute the boss threads
    108      * @param workerExecutor
    109      *        the {@link Executor} which will execute the I/O worker threads
    110      */
    111     public OioServerSocketChannelFactory(
    112             Executor bossExecutor, Executor workerExecutor) {
    113         if (bossExecutor == null) {
    114             throw new NullPointerException("bossExecutor");
    115         }
    116         if (workerExecutor == null) {
    117             throw new NullPointerException("workerExecutor");
    118         }
    119         this.bossExecutor = bossExecutor;
    120         this.workerExecutor = workerExecutor;
    121         sink = new OioServerSocketPipelineSink(workerExecutor);
    122     }
    123
    124     public ServerSocketChannel newChannel(ChannelPipeline pipeline) {
    125         return new OioServerSocketChannel(this, pipeline, sink);
    126     }
    127
    128     public void releaseExternalResources() {
    129         ExecutorUtil.terminate(bossExecutor, workerExecutor);
    130     }
    131 }