1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * Written by Doug Lea with assistance from members of JCP JSR-166
32  * Expert Group and released to the public domain, as explained at
33  * http://creativecommons.org/publicdomain/zero/1.0/
34  */
35 
36 package java.util.concurrent;
37 
38 import java.security.AccessController;
39 import java.security.PrivilegedAction;
40 
41 /**
42  * A thread managed by a {@link ForkJoinPool}, which executes
43  * {@link ForkJoinTask}s.
44  * This class is subclassable solely for the sake of adding
45  * functionality -- there are no overridable methods dealing with
46  * scheduling or execution.  However, you can override initialization
47  * and termination methods surrounding the main task processing loop.
48  * If you do create such a subclass, you will also need to supply a
49  * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
50  * {@linkplain ForkJoinPool#ForkJoinPool(int, ForkJoinWorkerThreadFactory,
51  * UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit)
52  * use it} in a {@code ForkJoinPool}.
53  *
54  * @since 1.7
55  * @author Doug Lea
56  */
57 public class ForkJoinWorkerThread extends Thread {
58     /*
59      * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
60      * ForkJoinTasks. For explanation, see the internal documentation
61      * of class ForkJoinPool.
62      *
63      * This class just maintains links to its pool and WorkQueue.
64      */
65 
66     final ForkJoinPool pool;                // the pool this thread works in
67     final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
68 
69     /**
70      * Full nonpublic constructor.
71      */
ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool, boolean useSystemClassLoader, boolean isInnocuous)72     ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool,
73                          boolean useSystemClassLoader, boolean isInnocuous) {
74         super(group, null, pool.nextWorkerThreadName(), 0L);
75         UncaughtExceptionHandler handler = (this.pool = pool).ueh;
76         this.workQueue = new ForkJoinPool.WorkQueue(this, isInnocuous);
77         super.setDaemon(true);
78         if (handler != null)
79             super.setUncaughtExceptionHandler(handler);
80         if (useSystemClassLoader)
81             super.setContextClassLoader(ClassLoader.getSystemClassLoader());
82     }
83 
84     /**
85      * Creates a ForkJoinWorkerThread operating in the given thread group and
86      * pool.
87      *
88      * @param group if non-null, the thread group for this thread
89      * @param pool the pool this thread works in
90      * @throws NullPointerException if pool is null
91      */
ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool)92     /* TODO: protected */ ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool) {
93         this(group, pool, false, false);
94     }
95 
96     /**
97      * Creates a ForkJoinWorkerThread operating in the given pool.
98      *
99      * @param pool the pool this thread works in
100      * @throws NullPointerException if pool is null
101      */
ForkJoinWorkerThread(ForkJoinPool pool)102     protected ForkJoinWorkerThread(ForkJoinPool pool) {
103         this(null, pool, false, false);
104     }
105 
106     /**
107      * Returns the pool hosting this thread.
108      *
109      * @return the pool
110      */
getPool()111     public ForkJoinPool getPool() {
112         return pool;
113     }
114 
115     /**
116      * Returns the unique index number of this thread in its pool.
117      * The returned value ranges from zero to the maximum number of
118      * threads (minus one) that may exist in the pool, and does not
119      * change during the lifetime of the thread.  This method may be
120      * useful for applications that track status or collect results
121      * per-worker-thread rather than per-task.
122      *
123      * @return the index number
124      */
getPoolIndex()125     public int getPoolIndex() {
126         return workQueue.getPoolIndex();
127     }
128 
129     /**
130      * Initializes internal state after construction but before
131      * processing any tasks. If you override this method, you must
132      * invoke {@code super.onStart()} at the beginning of the method.
133      * Initialization requires care: Most fields must have legal
134      * default values, to ensure that attempted accesses from other
135      * threads work correctly even before this thread starts
136      * processing tasks.
137      */
onStart()138     protected void onStart() {
139     }
140 
141     /**
142      * Performs cleanup associated with termination of this worker
143      * thread.  If you override this method, you must invoke
144      * {@code super.onTermination} at the end of the overridden method.
145      *
146      * @param exception the exception causing this thread to abort due
147      * to an unrecoverable error, or {@code null} if completed normally
148      */
onTermination(Throwable exception)149     protected void onTermination(Throwable exception) {
150     }
151 
152     /**
153      * This method is required to be public, but should never be
154      * called explicitly. It performs the main run loop to execute
155      * {@link ForkJoinTask}s.
156      */
run()157     public void run() {
158         Throwable exception = null;
159         ForkJoinPool p = pool;
160         ForkJoinPool.WorkQueue w = workQueue;
161         if (p != null && w != null) {   // skip on failed initialization
162             try {
163                 p.registerWorker(w);
164                 onStart();
165                 p.runWorker(w);
166             } catch (Throwable ex) {
167                 exception = ex;
168             } finally {
169                 try {
170                     onTermination(exception);
171                 } catch (Throwable ex) {
172                     if (exception == null)
173                         exception = ex;
174                 } finally {
175                     p.deregisterWorker(this, exception);
176                 }
177             }
178         }
179     }
180 
181     /**
182      * A worker thread that has no permissions, is not a member of any
183      * user-defined ThreadGroup, uses the system class loader as
184      * thread context class loader, and erases all ThreadLocals after
185      * running each top-level task.
186      */
187     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
188         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
189         @SuppressWarnings("removal")
190         private static final ThreadGroup innocuousThreadGroup =
191             AccessController.doPrivileged(new PrivilegedAction<>() {
192                 public ThreadGroup run() {
193                     ThreadGroup group = Thread.currentThread().getThreadGroup();
194                     for (ThreadGroup p; (p = group.getParent()) != null; )
195                         group = p;
196                     return new ThreadGroup(
197                         group, "InnocuousForkJoinWorkerThreadGroup");
198                 }});
199 
InnocuousForkJoinWorkerThread(ForkJoinPool pool)200         InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
201             super(innocuousThreadGroup, pool, true, true);
202         }
203 
204         @Override // to silently fail
setUncaughtExceptionHandler(UncaughtExceptionHandler x)205         public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
206 
207         @Override // paranoically
setContextClassLoader(ClassLoader cl)208         public void setContextClassLoader(ClassLoader cl) {
209             if (cl != null && ClassLoader.getSystemClassLoader() != cl)
210                 throw new SecurityException("setContextClassLoader");
211         }
212     }
213 }
214