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.nio;
17  
18  import java.nio.channels.Selector;
19  import java.util.concurrent.Executor;
20  import java.util.concurrent.Executors;
21  import java.util.concurrent.RejectedExecutionException;
22  
23  import org.jboss.netty.channel.Channel;
24  import org.jboss.netty.channel.ChannelPipeline;
25  import org.jboss.netty.channel.ChannelSink;
26  import org.jboss.netty.channel.group.ChannelGroup;
27  import org.jboss.netty.channel.socket.ServerSocketChannel;
28  import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
29  import org.jboss.netty.util.ExternalResourceReleasable;
30  import org.jboss.netty.util.internal.ExecutorUtil;
31  
32  /**
33   * A {@link ServerSocketChannelFactory} which creates a server-side NIO-based
34   * {@link ServerSocketChannel}.  It utilizes the non-blocking I/O mode which
35   * was introduced with NIO to serve many number of concurrent connections
36   * efficiently.
37   *
38   * <h3>How threads work</h3>
39   * <p>
40   * There are two types of threads in a {@link NioServerSocketChannelFactory};
41   * one is boss thread and the other is worker thread.
42   *
43   * <h4>Boss threads</h4>
44   * <p>
45   * Each bound {@link ServerSocketChannel} has its own boss thread.
46   * For example, if you opened two server ports such as 80 and 443, you will
47   * have two boss threads.  A boss thread accepts incoming connections until
48   * the port is unbound.  Once a connection is accepted successfully, the boss
49   * thread passes the accepted {@link Channel} to one of the worker
50   * threads that the {@link NioServerSocketChannelFactory} manages.
51   *
52   * <h4>Worker threads</h4>
53   * <p>
54   * One {@link NioServerSocketChannelFactory} can have one or more worker
55   * threads.  A worker thread performs non-blocking read and write for one or
56   * more {@link Channel}s in a non-blocking mode.
57   *
58   * <h3>Life cycle of threads and graceful shutdown</h3>
59   * <p>
60   * All threads are acquired from the {@link Executor}s which were specified
61   * when a {@link NioServerSocketChannelFactory} was created.  Boss threads are
62   * acquired from the {@code bossExecutor}, and worker threads are acquired from
63   * the {@code workerExecutor}.  Therefore, you should make sure the specified
64   * {@link Executor}s are able to lend the sufficient number of threads.
65   * It is the best bet to specify {@linkplain Executors#newCachedThreadPool() a cached thread pool}.
66   * <p>
67   * Both boss and worker threads are acquired lazily, and then released when
68   * there's nothing left to process.  All the related resources such as
69   * {@link Selector} are also released when the boss and worker threads are
70   * released.  Therefore, to shut down a service gracefully, you should do the
71   * following:
72   *
73   * <ol>
74   * <li>unbind all channels created by the factory,
75   * <li>close all child channels accepted by the unbound channels, and
76   *     (these two steps so far is usually done using {@link ChannelGroup#close()})</li>
77   * <li>call {@link #releaseExternalResources()}.</li>
78   * </ol>
79   *
80   * Please make sure not to shut down the executor until all channels are
81   * closed.  Otherwise, you will end up with a {@link RejectedExecutionException}
82   * and the related resources might not be released properly.
83   *
84   * @apiviz.landmark
85   */
86  public class NioServerSocketChannelFactory implements ServerSocketChannelFactory {
87  
88      final Executor bossExecutor;
89      private final WorkerPool<NioWorker> workerPool;
90      private final ChannelSink sink;
91  
92      /**
93       * Create a new {@link NioServerSocketChannelFactory} using {@link Executors#newCachedThreadPool()}
94       * for the boss and worker.
95       *
96       * See {@link #NioServerSocketChannelFactory(Executor, Executor)}
97       */
98      public NioServerSocketChannelFactory() {
99          this(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
100     }
101 
102     /**
103      * Creates a new instance.  Calling this constructor is same with calling
104      * {@link #NioServerSocketChannelFactory(Executor, Executor, int)} with 2 *
105      * the number of available processors in the machine.  The number of
106      * available processors is obtained by {@link Runtime#availableProcessors()}.
107      *
108      * @param bossExecutor
109      *        the {@link Executor} which will execute the boss threads
110      * @param workerExecutor
111      *        the {@link Executor} which will execute the I/O worker threads
112      */
113     public NioServerSocketChannelFactory(
114             Executor bossExecutor, Executor workerExecutor) {
115         this(bossExecutor, workerExecutor, SelectorUtil.DEFAULT_IO_THREADS);
116     }
117 
118     /**
119      * Creates a new instance.
120      *
121      * @param bossExecutor
122      *        the {@link Executor} which will execute the boss threads
123      * @param workerExecutor
124      *        the {@link Executor} which will execute the I/O worker threads
125      * @param workerCount
126      *        the maximum number of I/O worker threads
127      */
128     public NioServerSocketChannelFactory(
129             Executor bossExecutor, Executor workerExecutor,
130             int workerCount) {
131         this(bossExecutor, new NioWorkerPool(workerExecutor, workerCount));
132     }
133 
134     /**
135      * Creates a new instance.
136      *
137      * @param bossExecutor
138      *        the {@link Executor} which will execute the boss threads
139      * @param workerPool
140      *        the {@link WorkerPool} which will be used to obtain the {@link NioWorker} that execute
141      *        the I/O worker threads
142      */
143     public NioServerSocketChannelFactory(
144             Executor bossExecutor, WorkerPool<NioWorker> workerPool) {
145         if (bossExecutor == null) {
146             throw new NullPointerException("bossExecutor");
147         }
148         if (workerPool == null) {
149             throw new NullPointerException("workerPool");
150         }
151 
152         this.bossExecutor = bossExecutor;
153         this.workerPool = workerPool;
154         sink = new NioServerSocketPipelineSink(workerPool);
155     }
156 
157     public ServerSocketChannel newChannel(ChannelPipeline pipeline) {
158         return new NioServerSocketChannel(this, pipeline, sink);
159     }
160 
161     public void releaseExternalResources() {
162         ExecutorUtil.terminate(bossExecutor);
163         if (workerPool instanceof ExternalResourceReleasable) {
164             ((ExternalResourceReleasable) workerPool).releaseExternalResources();
165         }
166     }
167 }