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         // BEGIN Android-changed: System.getSecurityManager always returns null.
75         /*
76         if (System.getSecurityManager() == null) {
77             return (Runnable r) -> {
78                 Thread t = new Thread(r);
79                 t.setDaemon(true);
80                 return t;
81             };
82         } else {
83             return (Runnable r) -> {
84                 PrivilegedAction<Thread> action = () -> {
85                     Thread t = new sun.misc.InnocuousThread(r);
86                     t.setDaemon(true);
87                     return t;
88                };
89                return AccessController.doPrivileged(action);
90            };
91         }
92         */
93         return (Runnable r) -> {
94             Thread t = new Thread(r);
95             t.setDaemon(true);
96             return t;
97         };
98         // END Android-changed: System.getSecurityManager always returns null.
99     }
100 
101     private static class DefaultThreadPoolHolder {
102         final static ThreadPool defaultThreadPool = createDefault();
103     }
104 
105     // return the default (system-wide) thread pool
getDefault()106     static ThreadPool getDefault() {
107         return DefaultThreadPoolHolder.defaultThreadPool;
108     }
109 
110     // create thread using default settings (configured by system properties)
createDefault()111     static ThreadPool createDefault() {
112         // default the number of fixed threads to the hardware core count
113         int initialSize = getDefaultThreadPoolInitialSize();
114         if (initialSize < 0)
115             initialSize = Runtime.getRuntime().availableProcessors();
116         // default to thread factory that creates daemon threads
117         ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
118         if (threadFactory == null)
119             threadFactory = defaultThreadFactory();
120         // create thread pool
121         ExecutorService executor = Executors.newCachedThreadPool(threadFactory);
122         return new ThreadPool(executor, false, initialSize);
123     }
124 
125     // create using given parameters
create(int nThreads, ThreadFactory factory)126     static ThreadPool create(int nThreads, ThreadFactory factory) {
127         if (nThreads <= 0)
128             throw new IllegalArgumentException("'nThreads' must be > 0");
129         ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory);
130         return new ThreadPool(executor, true, nThreads);
131     }
132 
133     // wrap a user-supplied executor
wrap(ExecutorService executor, int initialSize)134     public static ThreadPool wrap(ExecutorService executor, int initialSize) {
135         if (executor == null)
136             throw new NullPointerException("'executor' is null");
137         // attempt to check if cached thread pool
138         if (executor instanceof ThreadPoolExecutor) {
139             int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize();
140             if (max == Integer.MAX_VALUE) {
141                 if (initialSize < 0) {
142                     initialSize = Runtime.getRuntime().availableProcessors();
143                 } else {
144                    // not a cached thread pool so ignore initial size
145                     initialSize = 0;
146                 }
147             }
148         } else {
149             // some other type of thread pool
150             if (initialSize < 0)
151                 initialSize = 0;
152         }
153         return new ThreadPool(executor, false, initialSize);
154     }
155 
getDefaultThreadPoolInitialSize()156     private static int getDefaultThreadPoolInitialSize() {
157         String propValue = AccessController.doPrivileged(new
158             GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE));
159         if (propValue != null) {
160             try {
161                 return Integer.parseInt(propValue);
162             } catch (NumberFormatException x) {
163                 throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE +
164                     "' is invalid: " + x);
165             }
166         }
167         return -1;
168     }
169 
getDefaultThreadPoolThreadFactory()170     private static ThreadFactory getDefaultThreadPoolThreadFactory() {
171         String propValue = AccessController.doPrivileged(new
172             GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY));
173         if (propValue != null) {
174             try {
175                 Class<?> c = Class
176                     .forName(propValue, true, ClassLoader.getSystemClassLoader());
177                 return ((ThreadFactory)c.newInstance());
178             } catch (ClassNotFoundException x) {
179                 throw new Error(x);
180             } catch (InstantiationException x) {
181                 throw new Error(x);
182             } catch (IllegalAccessException x) {
183                 throw new Error(x);
184             }
185         }
186         return null;
187     }
188 }
189