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