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