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.AccessControlContext;
  39 import java.security.AccessController;
  40 import java.security.PrivilegedAction;
  41 import java.security.ProtectionDomain;
  42 
  43 /**
  44  * A thread managed by a {@link ForkJoinPool}, which executes
  45  * {@link ForkJoinTask}s.
  46  * This class is subclassable solely for the sake of adding
  47  * functionality -- there are no overridable methods dealing with
  48  * scheduling or execution.  However, you can override initialization
  49  * and termination methods surrounding the main task processing loop.
  50  * If you do create such a subclass, you will also need to supply a
  51  * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
  52  * {@linkplain ForkJoinPool#ForkJoinPool 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.  The
  64      * pool field is set immediately upon construction, but the
  65      * workQueue field is not set until a call to registerWorker
  66      * completes. This leads to a visibility race, that is tolerated
  67      * by requiring that the workQueue field is only accessed by the
  68      * owning thread.
  69      *
  70      * Support for (non-public) subclass InnocuousForkJoinWorkerThread
  71      * requires that we break quite a lot of encapsulation (via helper
  72      * methods in ThreadLocalRandom) both here and in the subclass to
  73      * access and set Thread fields.
  74      */
  75 
  76     final ForkJoinPool pool;                // the pool this thread works in
  77     final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
  78 
  79     /**
  80      * Creates a ForkJoinWorkerThread operating in the given pool.
  81      *
  82      * @param pool the pool this thread works in
  83      * @throws NullPointerException if pool is null
  84      */
  85     protected ForkJoinWorkerThread(ForkJoinPool pool) {
  86         // Use a placeholder until a useful name can be set in registerWorker
  87         super("aForkJoinWorkerThread");
  88         this.pool = pool;
  89         this.workQueue = pool.registerWorker(this);
  90     }
  91 
  92     /**
  93      * Version for use by the default pool.  Supports setting the
  94      * context class loader.  This is a separate constructor to avoid
  95      * affecting the protected constructor.
  96      */
  97     ForkJoinWorkerThread(ForkJoinPool pool, ClassLoader ccl) {
  98         super("aForkJoinWorkerThread");
  99         super.setContextClassLoader(ccl);
 100         this.pool = pool;
 101         this.workQueue = pool.registerWorker(this);
 102     }
 103 
 104     /**
 105      * Version for InnocuousForkJoinWorkerThread.
 106      */
 107     ForkJoinWorkerThread(ForkJoinPool pool,
 108                          ClassLoader ccl,
 109                          ThreadGroup threadGroup,
 110                          AccessControlContext acc) {
 111         super(threadGroup, null, "aForkJoinWorkerThread");
 112         super.setContextClassLoader(ccl);
 113         ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
 114         ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
 115         this.pool = pool;
 116         this.workQueue = pool.registerWorker(this);
 117     }
 118 
 119     /**
 120      * Returns the pool hosting this thread.
 121      *
 122      * @return the pool
 123      */
 124     public ForkJoinPool getPool() {
 125         return pool;
 126     }
 127 
 128     /**
 129      * Returns the unique index number of this thread in its pool.
 130      * The returned value ranges from zero to the maximum number of
 131      * threads (minus one) that may exist in the pool, and does not
 132      * change during the lifetime of the thread.  This method may be
 133      * useful for applications that track status or collect results
 134      * per-worker-thread rather than per-task.
 135      *
 136      * @return the index number
 137      */
 138     public int getPoolIndex() {
 139         return workQueue.getPoolIndex();
 140     }
 141 
 142     /**
 143      * Initializes internal state after construction but before
 144      * processing any tasks. If you override this method, you must
 145      * invoke {@code super.onStart()} at the beginning of the method.
 146      * Initialization requires care: Most fields must have legal
 147      * default values, to ensure that attempted accesses from other
 148      * threads work correctly even before this thread starts
 149      * processing tasks.
 150      */
 151     protected void onStart() {
 152     }
 153 
 154     /**
 155      * Performs cleanup associated with termination of this worker
 156      * thread.  If you override this method, you must invoke
 157      * {@code super.onTermination} at the end of the overridden method.
 158      *
 159      * @param exception the exception causing this thread to abort due
 160      * to an unrecoverable error, or {@code null} if completed normally
 161      */
 162     protected void onTermination(Throwable exception) {
 163     }
 164 
 165     /**
 166      * This method is required to be public, but should never be
 167      * called explicitly. It performs the main run loop to execute
 168      * {@link ForkJoinTask}s.
 169      */
 170     public void run() {
 171         if (workQueue.array == null) { // only run once
 172             Throwable exception = null;
 173             try {
 174                 onStart();
 175                 pool.runWorker(workQueue);
 176             } catch (Throwable ex) {
 177                 exception = ex;
 178             } finally {
 179                 try {
 180                     onTermination(exception);
 181                 } catch (Throwable ex) {
 182                     if (exception == null)
 183                         exception = ex;
 184                 } finally {
 185                     pool.deregisterWorker(this, exception);
 186                 }
 187             }
 188         }
 189     }
 190 
 191     /**
 192      * Non-public hook method for InnocuousForkJoinWorkerThread.
 193      */
 194     void afterTopLevelExec() {
 195     }
 196 
 197     /**
 198      * A worker thread that has no permissions, is not a member of any
 199      * user-defined ThreadGroup, uses the system class loader as
 200      * thread context class loader, and erases all ThreadLocals after
 201      * running each top-level task.
 202      */
 203     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
 204         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
 205         private static final ThreadGroup innocuousThreadGroup =
 206             AccessController.doPrivileged(new PrivilegedAction<>() {
 207                 public ThreadGroup run() {
 208                     ThreadGroup group = Thread.currentThread().getThreadGroup();
 209                     for (ThreadGroup p; (p = group.getParent()) != null; )
 210                         group = p;
 211                     return new ThreadGroup(
 212                         group, "InnocuousForkJoinWorkerThreadGroup");
 213                 }});
 214 
 215         /** An AccessControlContext supporting no privileges */
 216         private static final AccessControlContext INNOCUOUS_ACC =
 217             new AccessControlContext(
 218                 new ProtectionDomain[] { new ProtectionDomain(null, null) });
 219 
 220         InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
 221             super(pool,
 222                   ClassLoader.getSystemClassLoader(),
 223                   innocuousThreadGroup,
 224                   INNOCUOUS_ACC);
 225         }
 226 
 227         @Override // to erase ThreadLocals
 228         void afterTopLevelExec() {
 229             ThreadLocalRandom.eraseThreadLocals(this);
 230         }
 231 
 232         @Override // to silently fail
 233         public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
 234 
 235         @Override // paranoically
 236         public void setContextClassLoader(ClassLoader cl) {
 237             throw new SecurityException("setContextClassLoader");
 238         }
 239     }
 240 }