ThreadPool.java revision 12745:f068a4ffddd2
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
26package sun.nio.ch;
27
28import java.util.concurrent.*;
29import java.security.AccessController;
30import java.security.PrivilegedAction;
31import sun.security.action.GetPropertyAction;
32import sun.security.action.GetIntegerAction;
33
34/**
35 * Encapsulates a thread pool associated with a channel group.
36 */
37
38public class ThreadPool {
39    private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY =
40        "java.nio.channels.DefaultThreadPool.threadFactory";
41    private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE =
42        "java.nio.channels.DefaultThreadPool.initialSize";
43
44    private final ExecutorService executor;
45
46    // indicates if thread pool is fixed size
47    private final boolean isFixed;
48
49    // indicates the pool size (for a fixed thread pool configuratin this is
50    // the maximum pool size; for other thread pools it is the initial size)
51    private final int poolSize;
52
53    private ThreadPool(ExecutorService executor,
54                       boolean isFixed,
55                       int poolSize)
56    {
57        this.executor = executor;
58        this.isFixed = isFixed;
59        this.poolSize = poolSize;
60    }
61
62    ExecutorService executor() {
63        return executor;
64    }
65
66    boolean isFixedThreadPool() {
67        return isFixed;
68    }
69
70    int poolSize() {
71        return poolSize;
72    }
73
74    static ThreadFactory defaultThreadFactory() {
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        static final ThreadPool defaultThreadPool = createDefault();
95    }
96
97    // return the default (system-wide) thread pool
98    static ThreadPool getDefault() {
99        return DefaultThreadPoolHolder.defaultThreadPool;
100    }
101
102    // create thread using default settings (configured by system properties)
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
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
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
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
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