View Javadoc

1   /*
2    * Copyright 2009 Red Hat, Inc.
3    *
4    * Red Hat licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * 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.RejectedExecutionException;
20  
21  import org.jboss.netty.channel.Channel;
22  import org.jboss.netty.channel.ChannelPipeline;
23  import org.jboss.netty.channel.group.ChannelGroup;
24  import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
25  import org.jboss.netty.channel.socket.SocketChannel;
26  import org.jboss.netty.util.internal.ExecutorUtil;
27  
28  /**
29   * A {@link ClientSocketChannelFactory} which creates a client-side blocking
30   * I/O based {@link SocketChannel}.  It utilizes the good old blocking I/O API
31   * which is known to yield better throughput and latency when there are
32   * relatively small number of connections to serve.
33   *
34   * <h3>How threads work</h3>
35   * <p>
36   * There is only one type of threads in {@link OioClientSocketChannelFactory};
37   * worker threads.
38   *
39   * <h4>Worker threads</h4>
40   * <p>
41   * Each connected {@link Channel} has a dedicated worker thread, just like a
42   * traditional blocking I/O thread model.
43   *
44   * <h3>Life cycle of threads and graceful shutdown</h3>
45   * <p>
46   * Worker threads are acquired from the {@link Executor} which was specified
47   * when a {@link OioClientSocketChannelFactory} was created (i.e. {@code workerExecutor}.)
48   * Therefore, you should make sure the specified {@link Executor} is able to
49   * lend the sufficient number of threads.
50   * <p>
51   * Worker threads are acquired lazily, and then released when there's nothing
52   * left to process.  All the related resources are also released when the
53   * worker threads are released.  Therefore, to shut down a service gracefully,
54   * you should do the following:
55   *
56   * <ol>
57   * <li>close all channels created by the factory usually using
58   *     {@link ChannelGroup#close()}, and</li>
59   * <li>call {@link #releaseExternalResources()}.</li>
60   * </ol>
61   *
62   * Please make sure not to shut down the executor until all channels are
63   * closed.  Otherwise, you will end up with a {@link RejectedExecutionException}
64   * and the related resources might not be released properly.
65   *
66   * <h3>Limitation</h3>
67   * <p>
68   * A {@link SocketChannel} created by this factory does not support asynchronous
69   * operations.  Any I/O requests such as {@code "connect"} and {@code "write"}
70   * will be performed in a blocking manner.
71   *
72   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
73   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
74   *
75   * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
76   *
77   * @apiviz.landmark
78   */
79  public class OioClientSocketChannelFactory implements ClientSocketChannelFactory {
80  
81      private final Executor workerExecutor;
82      final OioClientSocketPipelineSink sink;
83  
84      /**
85       * Creates a new instance.
86       *
87       * @param workerExecutor
88       *        the {@link Executor} which will execute the I/O worker threads
89       */
90      public OioClientSocketChannelFactory(Executor workerExecutor) {
91          if (workerExecutor == null) {
92              throw new NullPointerException("workerExecutor");
93          }
94          this.workerExecutor = workerExecutor;
95          sink = new OioClientSocketPipelineSink(workerExecutor);
96      }
97  
98      public SocketChannel newChannel(ChannelPipeline pipeline) {
99          return new OioClientSocketChannel(this, pipeline, sink);
100     }
101 
102     public void releaseExternalResources() {
103         ExecutorUtil.terminate(workerExecutor);
104     }
105 }