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.DatagramChannel;
26  import org.jboss.netty.channel.socket.DatagramChannelFactory;
27  import org.jboss.netty.util.ThreadNameDeterminer;
28  import org.jboss.netty.util.internal.ExecutorUtil;
29  
30  /**
31   * A {@link DatagramChannelFactory} which creates a blocking I/O based
32   * {@link DatagramChannel}.  It utilizes the good old blocking I/O API which
33   * has support for multicast.
34   *
35   * <h3>How threads work</h3>
36   * <p>
37   * There is only one type of threads in {@link OioDatagramChannelFactory};
38   * worker threads.
39   *
40   * <h4>Worker threads</h4>
41   * <p>
42   * Each {@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 OioDatagramChannelFactory} 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 DatagramChannel} created by this factory does not support asynchronous
70   * operations.  Any I/O requests such as {@code "write"} will be performed in a
71   * blocking manner.
72   *
73   * @apiviz.landmark
74   */
75  public class OioDatagramChannelFactory implements DatagramChannelFactory {
76  
77      private final Executor workerExecutor;
78      final OioDatagramPipelineSink sink;
79      private boolean shutdownExecutor;
80  
81      /**
82       * Creates a new instance with a {@link Executors#newCachedThreadPool()}
83       *
84       * See {@link #OioDatagramChannelFactory(Executor)}
85       */
86      public OioDatagramChannelFactory() {
87          this(Executors.newCachedThreadPool());
88          shutdownExecutor = true;
89      }
90  
91      /**
92       * Creates a new instance.
93       *
94       * @param workerExecutor
95       *        the {@link Executor} which will execute the I/O worker threads
96       */
97      public OioDatagramChannelFactory(Executor workerExecutor) {
98          this(workerExecutor, null);
99      }
100 
101     /**
102      * Creates a new instance.
103      *
104      * @param workerExecutor
105      *        the {@link Executor} which will execute the I/O worker threads
106      * @param determiner
107      *        the {@link ThreadNameDeterminer} to set the thread names.
108      */
109     public OioDatagramChannelFactory(Executor workerExecutor,
110                                      ThreadNameDeterminer determiner) {
111         if (workerExecutor == null) {
112             throw new NullPointerException("workerExecutor");
113         }
114         this.workerExecutor = workerExecutor;
115         sink = new OioDatagramPipelineSink(workerExecutor, determiner);
116     }
117 
118     public DatagramChannel newChannel(ChannelPipeline pipeline) {
119         return new OioDatagramChannel(this, pipeline, sink);
120     }
121 
122     public void shutdown() {
123         if (shutdownExecutor) {
124             ExecutorUtil.shutdownNow(workerExecutor);
125         }
126     }
127 
128     public void releaseExternalResources() {
129         ExecutorUtil.shutdownNow(workerExecutor);
130     }
131 }