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 import sun.security.action.GetIntegerAction; 33 import jdk.internal.misc.InnocuousThread; 34 35 /** 36 * Encapsulates a thread pool associated with a channel group. 37 */ 38 39 public class ThreadPool { 40 private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY = 41 "java.nio.channels.DefaultThreadPool.threadFactory"; 42 private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE = 43 "java.nio.channels.DefaultThreadPool.initialSize"; 44 45 private final ExecutorService executor; 46 47 // indicates if thread pool is fixed size 48 private final boolean isFixed; 49 50 // indicates the pool size (for a fixed thread pool configuratin this is 51 // the maximum pool size; for other thread pools it is the initial size) 52 private final int poolSize; 53 54 private ThreadPool(ExecutorService executor, 55 boolean isFixed, 56 int poolSize) 57 { 58 this.executor = executor; 59 this.isFixed = isFixed; 60 this.poolSize = poolSize; 61 } 62 63 ExecutorService executor() { 64 return executor; 65 } 66 67 boolean isFixedThreadPool() { 68 return isFixed; 69 } 70 71 int poolSize() { 72 return poolSize; 73 } 74 75 static ThreadFactory defaultThreadFactory() { 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 = InnocuousThread.newThread(r); 86 t.setDaemon(true); 87 return t; 88 }; 89 return AccessController.doPrivileged(action); 90 }; 91 } 92 } 93 94 private static class DefaultThreadPoolHolder { 95 static final ThreadPool defaultThreadPool = createDefault(); 96 } 97 98 // return the default (system-wide) thread pool 99 static ThreadPool getDefault() { 100 return DefaultThreadPoolHolder.defaultThreadPool; 101 } 102 103 // create thread using default settings (configured by system properties) 104 static ThreadPool createDefault() { 105 // default the number of fixed threads to the hardware core count 106 int initialSize = getDefaultThreadPoolInitialSize(); 107 if (initialSize < 0) 108 initialSize = Runtime.getRuntime().availableProcessors(); 109 // default to thread factory that creates daemon threads 110 ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory(); 111 if (threadFactory == null) 112 threadFactory = defaultThreadFactory(); 113 // create thread pool 114 ExecutorService executor = Executors.newCachedThreadPool(threadFactory); 115 return new ThreadPool(executor, false, initialSize); 116 } 117 118 // create using given parameters 119 static ThreadPool create(int nThreads, ThreadFactory factory) { 120 if (nThreads <= 0) 121 throw new IllegalArgumentException("'nThreads' must be > 0"); 122 ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory); 123 return new ThreadPool(executor, true, nThreads); 124 } 125 126 // wrap a user-supplied executor 127 public static ThreadPool wrap(ExecutorService executor, int initialSize) { 128 if (executor == null) 129 throw new NullPointerException("'executor' is null"); 130 // attempt to check if cached thread pool 131 if (executor instanceof ThreadPoolExecutor) { 132 int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize(); 133 if (max == Integer.MAX_VALUE) { 134 if (initialSize < 0) { 135 initialSize = Runtime.getRuntime().availableProcessors(); 136 } else { 137 // not a cached thread pool so ignore initial size 138 initialSize = 0; 139 } 140 } 141 } else { 142 // some other type of thread pool 143 if (initialSize < 0) 144 initialSize = 0; 145 } 146 return new ThreadPool(executor, false, initialSize); 147 } 148 149 private static int getDefaultThreadPoolInitialSize() { 150 String propValue = AccessController.doPrivileged(new 151 GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE)); 152 if (propValue != null) { 153 try { 154 return Integer.parseInt(propValue); 155 } catch (NumberFormatException x) { 156 throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE + 157 "' is invalid: " + x); 158 } 159 } 160 return -1; 161 } 162 163 private static ThreadFactory getDefaultThreadPoolThreadFactory() { 164 String propValue = AccessController.doPrivileged(new 165 GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY)); 166 if (propValue != null) { 167 try { 168 @SuppressWarnings("deprecation") 169 Object tmp = Class 170 .forName(propValue, true, ClassLoader.getSystemClassLoader()).newInstance(); 171 return (ThreadFactory)tmp; 172 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException x) { 173 throw new Error(x); 174 } 175 } 176 return null; 177 } 178 }