ForkJoinWorkerThread.java revision 75a06e56a4cc4599946e21422513e4bafa759509
1/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7package java.util.concurrent;
8
9/**
10 * A thread managed by a {@link ForkJoinPool}, which executes
11 * {@link ForkJoinTask}s.
12 * This class is subclassable solely for the sake of adding
13 * functionality -- there are no overridable methods dealing with
14 * scheduling or execution.  However, you can override initialization
15 * and termination methods surrounding the main task processing loop.
16 * If you do create such a subclass, you will also need to supply a
17 * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
18 * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
19 *
20 * @since 1.7
21 * @hide
22 * @author Doug Lea
23 */
24public class ForkJoinWorkerThread extends Thread {
25    /*
26     * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
27     * ForkJoinTasks. For explanation, see the internal documentation
28     * of class ForkJoinPool.
29     *
30     * This class just maintains links to its pool and WorkQueue.  The
31     * pool field is set immediately upon construction, but the
32     * workQueue field is not set until a call to registerWorker
33     * completes. This leads to a visibility race, that is tolerated
34     * by requiring that the workQueue field is only accessed by the
35     * owning thread.
36     */
37
38    final ForkJoinPool pool;                // the pool this thread works in
39    final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
40
41    /**
42     * Creates a ForkJoinWorkerThread operating in the given pool.
43     *
44     * @param pool the pool this thread works in
45     * @throws NullPointerException if pool is null
46     */
47    protected ForkJoinWorkerThread(ForkJoinPool pool) {
48        // Use a placeholder until a useful name can be set in registerWorker
49        super("aForkJoinWorkerThread");
50        this.pool = pool;
51        this.workQueue = pool.registerWorker(this);
52    }
53
54    /**
55     * Returns the pool hosting this thread.
56     *
57     * @return the pool
58     */
59    public ForkJoinPool getPool() {
60        return pool;
61    }
62
63    /**
64     * Returns the unique index number of this thread in its pool.
65     * The returned value ranges from zero to the maximum number of
66     * threads (minus one) that may exist in the pool, and does not
67     * change during the lifetime of the thread.  This method may be
68     * useful for applications that track status or collect results
69     * per-worker-thread rather than per-task.
70     *
71     * @return the index number
72     */
73    public int getPoolIndex() {
74        return workQueue.poolIndex >>> 1; // ignore odd/even tag bit
75    }
76
77    /**
78     * Initializes internal state after construction but before
79     * processing any tasks. If you override this method, you must
80     * invoke {@code super.onStart()} at the beginning of the method.
81     * Initialization requires care: Most fields must have legal
82     * default values, to ensure that attempted accesses from other
83     * threads work correctly even before this thread starts
84     * processing tasks.
85     */
86    protected void onStart() {
87    }
88
89    /**
90     * Performs cleanup associated with termination of this worker
91     * thread.  If you override this method, you must invoke
92     * {@code super.onTermination} at the end of the overridden method.
93     *
94     * @param exception the exception causing this thread to abort due
95     * to an unrecoverable error, or {@code null} if completed normally
96     */
97    protected void onTermination(Throwable exception) {
98    }
99
100    /**
101     * This method is required to be public, but should never be
102     * called explicitly. It performs the main run loop to execute
103     * {@link ForkJoinTask}s.
104     */
105    public void run() {
106        Throwable exception = null;
107        try {
108            onStart();
109            pool.runWorker(workQueue);
110        } catch (Throwable ex) {
111            exception = ex;
112        } finally {
113            try {
114                onTermination(exception);
115            } catch (Throwable ex) {
116                if (exception == null)
117                    exception = ex;
118            } finally {
119                pool.deregisterWorker(this, exception);
120            }
121        }
122    }
123}
124