View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.mina.common;
21  
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import org.apache.mina.filter.executor.ExecutorFilter;
26  import org.apache.mina.util.NamePreservingRunnable;
27  
28  import edu.emory.mathcs.backport.java.util.concurrent.Executor;
29  import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
30  import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
31  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
32  
33  /**
34   * A {@link ThreadModel} which represents a thread model with an {@link Executor}
35   * (from <a href="http://dcl.mathcs.emory.edu/util/backport-util-concurrent/">backport-util-concurrent</a>)
36   * per service.  The default underlying {@link Executor} is {@link ThreadPoolExecutor},
37   * so you can safely downcast the returned {@link Executor} of {@link #getExecutor()} to
38   * {@link ThreadPoolExecutor} by default.
39   * 
40   * @author The Apache Directory Project (mina-dev@directory.apache.org)
41   * @version $Rev: 588150 $, $Date: 2007-10-25 15:20:04 +0900 (목, 25 10월 2007) $
42   */
43  public class ExecutorThreadModel implements ThreadModel {
44      /**
45       * Maps a service name to a PooledThreadModel instance.
46       * Without this map, we might create extremely many thread pools that leads the system to
47       * coma. */
48      private static final Map service2model = new HashMap();
49  
50      /**
51       * Returns a {@link ExecutorThreadModel} instance for the specified <tt>serviceName</tt>.
52       * Please note that all returned instances will be managed globally; the same instance
53       * will be returned if you specified the same service name.  Please try to specify
54       * different names for different services.
55       * 
56       * @param serviceName the name of the service that needs thread pooling
57       */
58      public static ExecutorThreadModel getInstance(String serviceName) {
59          if (serviceName == null) {
60              throw new NullPointerException("serviceName");
61          }
62  
63          ExecutorThreadModel model;
64          synchronized (service2model) {
65              model = (ExecutorThreadModel) service2model.get(serviceName);
66              if (model == null) {
67                  model = new ExecutorThreadModel(serviceName);
68                  service2model.put(serviceName, model);
69              }
70          }
71  
72          return model;
73      }
74  
75      private final String threadNamePrefix;
76  
77      private final ExecutorFilter defaultFilter;
78  
79      private ExecutorFilter filter = new ExecutorFilter();
80  
81      private ExecutorThreadModel(String threadNamePrefix) {
82          this.threadNamePrefix = threadNamePrefix;
83  
84          // Create the default filter
85          defaultFilter = new ExecutorFilter();
86          ThreadPoolExecutor tpe = (ThreadPoolExecutor) defaultFilter
87                  .getExecutor();
88          final ThreadFactory originalThreadFactory = tpe.getThreadFactory();
89          ThreadFactory newThreadFactory = new ThreadFactory() {
90              private final AtomicInteger threadId = new AtomicInteger(0);
91  
92              public Thread newThread(Runnable runnable) {
93                  Thread t = originalThreadFactory.newThread(
94                          new NamePreservingRunnable(
95                                  runnable, 
96                                  ExecutorThreadModel.this.threadNamePrefix + '-' +
97                                  threadId.incrementAndGet()));
98                  t.setDaemon(true);
99                  return t;
100             }
101         };
102         tpe.setThreadFactory(newThreadFactory);
103 
104         // Set to default.
105         setExecutor(null);
106     }
107 
108     /**
109      * Returns the underlying {@link Executor} of this model.
110      * You can change various properties such as the number of threads
111      * by calling methods of the {@link Executor} implementation.
112      */
113     public Executor getExecutor() {
114         return filter.getExecutor();
115     }
116 
117     /**
118      * Changes the underlying {@link Executor} of this model.
119      * Previous settings such as the number of threads should be configured again.
120      * Only newly created {@link IoSession}s will be affected.
121      * 
122      * @param executor <tt>null</tt> to revert to the default setting
123      */
124     public void setExecutor(Executor executor) {
125         if (executor == null) {
126             filter = defaultFilter;
127         } else {
128             filter = new ExecutorFilter(executor);
129         }
130     }
131 
132     public void buildFilterChain(IoFilterChain chain) throws Exception {
133         chain.addFirst(ExecutorThreadModel.class.getName(), filter);
134     }
135 }