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 use it
18 * 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 index number of this thread in its pool.  The
65     * returned value ranges from zero to the maximum number of
66     * threads (minus one) that have ever been created in the pool.
67     * This method may be useful for applications that track status or
68     * collect results per-worker rather than per-task.
69     *
70     * @return the index number
71     */
72    public int getPoolIndex() {
73        return workQueue.poolIndex;
74    }
75
76    /**
77     * Initializes internal state after construction but before
78     * processing any tasks. If you override this method, you must
79     * invoke {@code super.onStart()} at the beginning of the method.
80     * Initialization requires care: Most fields must have legal
81     * default values, to ensure that attempted accesses from other
82     * threads work correctly even before this thread starts
83     * processing tasks.
84     */
85    protected void onStart() {
86    }
87
88    /**
89     * Performs cleanup associated with termination of this worker
90     * thread.  If you override this method, you must invoke
91     * {@code super.onTermination} at the end of the overridden method.
92     *
93     * @param exception the exception causing this thread to abort due
94     * to an unrecoverable error, or {@code null} if completed normally
95     */
96    protected void onTermination(Throwable exception) {
97    }
98
99    /**
100     * This method is required to be public, but should never be
101     * called explicitly. It performs the main run loop to execute
102     * {@link ForkJoinTask}s.
103     */
104    public void run() {
105        Throwable exception = null;
106        try {
107            onStart();
108            pool.runWorker(workQueue);
109        } catch (Throwable ex) {
110            exception = ex;
111        } finally {
112            try {
113                onTermination(exception);
114            } catch (Throwable ex) {
115                if (exception == null)
116                    exception = ex;
117            } finally {
118                pool.deregisterWorker(this, exception);
119            }
120        }
121    }
122}
123