1 /*
2  * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.nio.ch;
27 
28 import java.util.concurrent.*;
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31 import sun.security.action.GetPropertyAction;
32 
33 /**
34  * Encapsulates a thread pool associated with a channel group.
35  */
36 
37 public class ThreadPool {
38     private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY =
39         "java.nio.channels.DefaultThreadPool.threadFactory";
40     private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE =
41         "java.nio.channels.DefaultThreadPool.initialSize";
42 
43     private final ExecutorService executor;
44 
45     // indicates if thread pool is fixed size
46     private final boolean isFixed;
47 
48     // indicates the pool size (for a fixed thread pool configuratin this is
49     // the maximum pool size; for other thread pools it is the initial size)
50     private final int poolSize;
51 
ThreadPool(ExecutorService executor, boolean isFixed, int poolSize)52     private ThreadPool(ExecutorService executor,
53                        boolean isFixed,
54                        int poolSize)
55     {
56         this.executor = executor;
57         this.isFixed = isFixed;
58         this.poolSize = poolSize;
59     }
60 
executor()61     ExecutorService executor() {
62         return executor;
63     }
64 
isFixedThreadPool()65     boolean isFixedThreadPool() {
66         return isFixed;
67     }
68 
poolSize()69     int poolSize() {
70         return poolSize;
71     }
72 
defaultThreadFactory()73     static ThreadFactory defaultThreadFactory() {
74         // Android-changed: System.getSecurityManager always returns null.
75         // if (System.getSecurityManager() == null) {
76         return (Runnable r) -> {
77             Thread t = new Thread(r);
78             t.setDaemon(true);
79             return t;
80         };
81         // } else {
82         //    return (Runnable r) -> {
83         //        PrivilegedAction<Thread> action = () -> {
84         //            Thread t = new sun.misc.InnocuousThread(r);
85         //            t.setDaemon(true);
86         //            return t;
87         //       };
88         //       return AccessController.doPrivileged(action);
89         //   };
90         // }
91     }
92 
93     private static class DefaultThreadPoolHolder {
94         final static ThreadPool defaultThreadPool = createDefault();
95     }
96 
97     // return the default (system-wide) thread pool
getDefault()98     static ThreadPool getDefault() {
99         return DefaultThreadPoolHolder.defaultThreadPool;
100     }
101 
102     // create thread using default settings (configured by system properties)
createDefault()103     static ThreadPool createDefault() {
104         // default the number of fixed threads to the hardware core count
105         int initialSize = getDefaultThreadPoolInitialSize();
106         if (initialSize < 0)
107             initialSize = Runtime.getRuntime().availableProcessors();
108         // default to thread factory that creates daemon threads
109         ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
110         if (threadFactory == null)
111             threadFactory = defaultThreadFactory();
112         // create thread pool
113         ExecutorService executor = Executors.newCachedThreadPool(threadFactory);
114         return new ThreadPool(executor, false, initialSize);
115     }
116 
117     // create using given parameters
create(int nThreads, ThreadFactory factory)118     static ThreadPool create(int nThreads, ThreadFactory factory) {
119         if (nThreads <= 0)
120             throw new IllegalArgumentException("'nThreads' must be > 0");
121         ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory);
122         return new ThreadPool(executor, true, nThreads);
123     }
124 
125     // wrap a user-supplied executor
wrap(ExecutorService executor, int initialSize)126     public static ThreadPool wrap(ExecutorService executor, int initialSize) {
127         if (executor == null)
128             throw new NullPointerException("'executor' is null");
129         // attempt to check if cached thread pool
130         if (executor instanceof ThreadPoolExecutor) {
131             int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize();
132             if (max == Integer.MAX_VALUE) {
133                 if (initialSize < 0) {
134                     initialSize = Runtime.getRuntime().availableProcessors();
135                 } else {
136                    // not a cached thread pool so ignore initial size
137                     initialSize = 0;
138                 }
139             }
140         } else {
141             // some other type of thread pool
142             if (initialSize < 0)
143                 initialSize = 0;
144         }
145         return new ThreadPool(executor, false, initialSize);
146     }
147 
getDefaultThreadPoolInitialSize()148     private static int getDefaultThreadPoolInitialSize() {
149         String propValue = AccessController.doPrivileged(new
150             GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE));
151         if (propValue != null) {
152             try {
153                 return Integer.parseInt(propValue);
154             } catch (NumberFormatException x) {
155                 throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE +
156                     "' is invalid: " + x);
157             }
158         }
159         return -1;
160     }
161 
getDefaultThreadPoolThreadFactory()162     private static ThreadFactory getDefaultThreadPoolThreadFactory() {
163         String propValue = AccessController.doPrivileged(new
164             GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY));
165         if (propValue != null) {
166             try {
167                 Class<?> c = Class
168                     .forName(propValue, true, ClassLoader.getSystemClassLoader());
169                 return ((ThreadFactory)c.newInstance());
170             } catch (ClassNotFoundException x) {
171                 throw new Error(x);
172             } catch (InstantiationException x) {
173                 throw new Error(x);
174             } catch (IllegalAccessException x) {
175                 throw new Error(x);
176             }
177         }
178         return null;
179     }
180 }
181